// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "core/internal/encryption_runner.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/time/clock.h" #include "core/internal/client_proxy.h" #include "core/internal/endpoint_channel.h" #include "platform/base/byte_array.h" #include "platform/public/count_down_latch.h" #include "platform/public/pipe.h" #include "platform/public/system_clock.h" #include "proto/connections_enums.pb.h" namespace location { namespace nearby { namespace connections { namespace { using ::location::nearby::proto::connections::Medium; class FakeEndpointChannel : public EndpointChannel { public: FakeEndpointChannel(InputStream* in, OutputStream* out) : in_(in), out_(out) {} ExceptionOr Read() override { read_timestamp_ = SystemClock::ElapsedRealtime(); return in_ ? in_->Read(Pipe::kChunkSize) : ExceptionOr{Exception::kIo}; } Exception Write(const ByteArray& data) override { write_timestamp_ = SystemClock::ElapsedRealtime(); return out_ ? out_->Write(data) : Exception{Exception::kIo}; } void Close() override { if (in_) in_->Close(); if (out_) out_->Close(); } void Close(proto::connections::DisconnectionReason reason) override { Close(); } // TODO(jfcarroll): This needs to be fixed properly proto::connections::ConnectionTechnology GetTechnology() const override { return proto::connections::ConnectionTechnology:: CONNECTION_TECHNOLOGY_BLE_GATT; } // TODO(jfcarroll): This needs to be fixed properly proto::connections::ConnectionBand GetBand() const override { return proto::connections::ConnectionBand::CONNECTION_BAND_CELLULAR_BAND_2G; } // TODO(jfcarroll): This needs to be fixed properly int GetFrequency() const override { return 0; } // TODO(jfcarroll): This needs to be fixed properly int GetTryCount() const override { return 0; } std::string GetType() const override { return "fake-channel-type"; } std::string GetName() const override { return "fake-channel"; } Medium GetMedium() const override { return Medium::BLE; } int GetMaxTransmitPacketSize() const override { return 512; } void EnableEncryption(std::shared_ptr context) override {} void DisableEncryption() override {} bool IsPaused() const override { return false; } void Pause() override {} void Resume() override {} absl::Time GetLastReadTimestamp() const override { return read_timestamp_; } absl::Time GetLastWriteTimestamp() const override { return write_timestamp_; } void SetAnalyticsRecorder(analytics::AnalyticsRecorder* analytics_recorder, const std::string& endpoint_id) override {} private: InputStream* in_ = nullptr; OutputStream* out_ = nullptr; absl::Time read_timestamp_ = absl::InfinitePast(); absl::Time write_timestamp_ = absl::InfinitePast(); }; struct User { User(Pipe* reader, Pipe* writer) : channel(&reader->GetInputStream(), &writer->GetOutputStream()) {} FakeEndpointChannel channel; EncryptionRunner crypto; ClientProxy client; }; struct Response { enum class Status { kUnknown = 0, kDone = 1, kFailed = 2, }; CountDownLatch latch{2}; Status server_status = Status::kUnknown; Status client_status = Status::kUnknown; }; TEST(EncryptionRunnerTest, ConstructorDestructorWorks) { EncryptionRunner enc; } TEST(EncryptionRunnerTest, ReadWrite) { Pipe from_a_to_b; Pipe from_b_to_a; User user_a(/*reader=*/&from_b_to_a, /*writer=*/&from_a_to_b); User user_b(/*reader=*/&from_a_to_b, /*writer=*/&from_b_to_a); Response response; user_a.crypto.StartServer( &user_a.client, "endpoint_id", &user_a.channel, { .on_success_cb = [&response](const std::string& endpoint_id, std::unique_ptr ukey2, const std::string& auth_token, const ByteArray& raw_auth_token) { response.server_status = Response::Status::kDone; response.latch.CountDown(); }, .on_failure_cb = [&response](const std::string& endpoint_id, EndpointChannel* channel) { response.server_status = Response::Status::kFailed; response.latch.CountDown(); }, }); user_b.crypto.StartClient( &user_b.client, "endpoint_id", &user_b.channel, { .on_success_cb = [&response](const std::string& endpoint_id, std::unique_ptr ukey2, const std::string& auth_token, const ByteArray& raw_auth_token) { response.client_status = Response::Status::kDone; response.latch.CountDown(); }, .on_failure_cb = [&response](const std::string& endpoint_id, EndpointChannel* channel) { response.client_status = Response::Status::kFailed; response.latch.CountDown(); }, }); EXPECT_TRUE(response.latch.Await(absl::Milliseconds(5000)).result()); EXPECT_EQ(response.server_status, Response::Status::kDone); EXPECT_EQ(response.client_status, Response::Status::kDone); } } // namespace } // namespace connections } // namespace nearby } // namespace location