diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index 2d03dcd2..334c01a7 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -31,14 +31,14 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - with: - submodules: recursive + # Disbale layering_check to work around ABSL build failure. + # see https://github.com/bazelbuild/bazel/issues/15359 - name: Build Connections - run: CC=clang CXX=clang++ bazel build --check_visibility=false //connections:core --spawn_strategy=standalone + run: CC=clang CXX=clang++ bazel build --features=-layering_check //connections:core --spawn_strategy=standalone - name: Build Presence - run: CC=clang CXX=clang++ bazel build --check_visibility=false //presence --spawn_strategy=standalone + run: CC=clang CXX=clang++ bazel build --features=-layering_check //presence --spawn_strategy=standalone - name: Build Sharing - run: CC=clang CXX=clang++ bazel build --check_visibility=false //sharing/proto:all --spawn_strategy=standalone + run: CC=clang CXX=clang++ bazel build --features=-layering_check //sharing/proto:all //sharing/internal/public:nearby_context //sharing/common:all //sharing/scheduling:scheduling --spawn_strategy=standalone build-rust-linux: name: Build Rust on Linux diff --git a/WORKSPACE b/WORKSPACE index 5ff5e67f..052d8da6 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,17 +1,17 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Rule repository, note that it's recommended to use a pinned commit to a released version of the rules -http_archive( - name = "rules_foreign_cc", - strip_prefix = "rules_foreign_cc-0.6.0", - url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.6.0.tar.gz", -) +# http_archive( +# name = "rules_foreign_cc", +# strip_prefix = "rules_foreign_cc-0.6.0", +# url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.6.0.tar.gz", +#) -load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") +# load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") # This sets up some common toolchains for building targets. For more details, please see # https://github.com/bazelbuild/rules_foreign_cc/tree/main/docs#rules_foreign_cc_dependencies -rules_foreign_cc_dependencies() +# rules_foreign_cc_dependencies() _ALL_CONTENT = """\ filegroup( @@ -21,10 +21,24 @@ filegroup( ) """ +http_archive( + name = "bazel_skylib", # 2023-05-31T19:24:07Z + sha256 = "08c0386f45821ce246bbbf77503c973246ed6ee5c3463e41efc197fa9bc3a7f4", + strip_prefix = "bazel-skylib-288731ef9f7f688932bd50e704a91a45ec185f9b", + urls = ["https://github.com/bazelbuild/bazel-skylib/archive/288731ef9f7f688932bd50e704a91a45ec185f9b.zip"], +) + +http_archive( + name = "platforms", # 2023-07-28T19:44:27Z + sha256 = "40eb313613ff00a5c03eed20aba58890046f4d38dec7344f00bb9a8867853526", + strip_prefix = "platforms-4ad40ef271da8176d4fc0194d2089b8a76e19d7b", + urls = ["https://github.com/bazelbuild/platforms/archive/4ad40ef271da8176d4fc0194d2089b8a76e19d7b.zip"], +) + http_archive( name = "com_google_absl", - strip_prefix = "abseil-cpp-20230802.1", - urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20230802.1.zip"], + strip_prefix = "abseil-cpp-4038192a57cb75f7ee671f81a3378ff4c74c4f8e", + urls = ["https://github.com/abseil/abseil-cpp/archive/4038192a57cb75f7ee671f81a3378ff4c74c4f8e.zip"], ) # Using a protobuf javalite version that contains @com_google_protobuf_javalite//:javalite_toolchain diff --git a/connections/BUILD b/connections/BUILD index bbe2b62a..2ab67e4c 100644 --- a/connections/BUILD +++ b/connections/BUILD @@ -27,7 +27,7 @@ cc_library( "//connections:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", "//location/nearby/testing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":core_types", @@ -74,7 +74,7 @@ cc_library( "//connections:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", "//location/nearby/testing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//internal/platform:base", diff --git a/connections/implementation/BUILD b/connections/implementation/BUILD index 4491e930..ee9cac0b 100644 --- a/connections/implementation/BUILD +++ b/connections/implementation/BUILD @@ -110,7 +110,7 @@ cc_library( "//connections:__pkg__", "//connections/implementation/fuzzers:__pkg__", "//location/nearby/cpp/sharing/implementation:__pkg__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//connections:core_types", diff --git a/internal/analytics/BUILD b/internal/analytics/BUILD index 4d6bfc2d..bc15387e 100644 --- a/internal/analytics/BUILD +++ b/internal/analytics/BUILD @@ -24,7 +24,7 @@ cc_library( "//location/nearby/analytics/cpp:__subpackages__", "//location/nearby/cpp/experiments:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = ["@com_google_protobuf//:protobuf"], ) diff --git a/internal/base/BUILD b/internal/base/BUILD index 35d66268..99450c74 100644 --- a/internal/base/BUILD +++ b/internal/base/BUILD @@ -18,7 +18,7 @@ cc_library( "//internal/test:__pkg__", "//location/nearby/cpp/experiments:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//internal/platform:types", @@ -42,7 +42,7 @@ cc_library( "//fastpair:__subpackages__", "//internal:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "@com_google_absl//absl/strings", diff --git a/internal/network/BUILD b/internal/network/BUILD index 52f6f3de..0620b329 100644 --- a/internal/network/BUILD +++ b/internal/network/BUILD @@ -24,7 +24,7 @@ cc_library( "//internal:__pkg__", "//internal:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//internal/platform:types", @@ -53,7 +53,7 @@ cc_library( "//internal:__pkg__", "//internal:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":types", diff --git a/internal/platform/BUILD b/internal/platform/BUILD index 0e5a61e1..2f151ab9 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -56,7 +56,7 @@ cc_library( "//internal/weave:__subpackages__", "//location/nearby/cpp:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//proto:connections_enums_cc_proto", @@ -197,7 +197,7 @@ cc_library( "//fastpair:__subpackages__", "//internal/platform/implementation:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":base", @@ -347,7 +347,7 @@ cc_library( "//location/nearby/cpp:__subpackages__", "//location/nearby/testing/nearby_native:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":base", diff --git a/internal/platform/implementation/BUILD b/internal/platform/implementation/BUILD index 3b11e279..a8194618 100644 --- a/internal/platform/implementation/BUILD +++ b/internal/platform/implementation/BUILD @@ -53,7 +53,7 @@ cc_library( "//location/nearby/cpp/common:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ "//internal/crypto_cros", @@ -126,7 +126,7 @@ cc_library( "//internal/platform/implementation:__subpackages__", "//location/nearby/analytics/cpp:__subpackages__", "//location/nearby/cpp/sharing:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":comm", diff --git a/internal/platform/implementation/apple/BUILD b/internal/platform/implementation/apple/BUILD index 0e2b044e..5b0914ce 100644 --- a/internal/platform/implementation/apple/BUILD +++ b/internal/platform/implementation/apple/BUILD @@ -17,7 +17,7 @@ package(default_visibility = [ "//connections:__subpackages__", "//internal/platform/implementation/apple:__subpackages__", "//location/nearby:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ]) objc_library( diff --git a/internal/platform/implementation/g3/BUILD b/internal/platform/implementation/g3/BUILD index 9a4359d6..db01a738 100644 --- a/internal/platform/implementation/g3/BUILD +++ b/internal/platform/implementation/g3/BUILD @@ -38,7 +38,7 @@ cc_library( visibility = [ "//internal/test:__subpackages__", "//location/nearby/cpp:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":preferences_repository", @@ -155,7 +155,7 @@ cc_library( "//internal/weave:__subpackages__", "//location/nearby/cpp:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":comm", diff --git a/internal/platform/implementation/windows/BUILD b/internal/platform/implementation/windows/BUILD index 31abb0a9..ae26985a 100644 --- a/internal/platform/implementation/windows/BUILD +++ b/internal/platform/implementation/windows/BUILD @@ -47,7 +47,7 @@ cc_library( "-Wno-vla-extension", ], defines = ["_SILENCE_CLANG_COROUTINE_MESSAGE"], - visibility = ["//third_party/nearby/sharing/internal/impl/windows:__pkg__"], + visibility = ["//sharing/internal/impl/windows:__pkg__"], deps = [ ":comm", "//base", @@ -207,7 +207,7 @@ cc_library( "//fastpair:__subpackages__", "//location/nearby:__subpackages__", "//presence:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], deps = [ ":comm", diff --git a/internal/platform/implementation/windows/generated/BUILD b/internal/platform/implementation/windows/generated/BUILD index 1036e17b..6434f51d 100644 --- a/internal/platform/implementation/windows/generated/BUILD +++ b/internal/platform/implementation/windows/generated/BUILD @@ -46,6 +46,6 @@ cc_library( "//internal:__subpackages__", "//internal/platform/implementation/windows:__subpackages__", "//location/nearby/cpp/sharing/implementation/internal:__subpackages__", - "//third_party/nearby/sharing:__subpackages__", + "//sharing:__subpackages__", ], ) diff --git a/sharing/common/BUILD b/sharing/common/BUILD new file mode 100644 index 00000000..a46bee3a --- /dev/null +++ b/sharing/common/BUILD @@ -0,0 +1,69 @@ +# Copyright 2024 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. + +licenses(["notice"]) + +cc_library( + name = "common", + srcs = [ + "nearby_share_prefs.cc", + "nearby_share_switches.cc", + ], + hdrs = [ + "nearby_share_enums.h", + "nearby_share_prefs.h", + "nearby_share_profile_info_provider.h", + "nearby_share_switches.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//sharing/internal/api:platform", + "//sharing/proto:share_cc_proto", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "test_support", + testonly = True, + srcs = [ + "fake_nearby_share_profile_info_provider.cc", + ], + hdrs = [ + "fake_nearby_share_profile_info_provider.h", + "nearby_share_profile_info_provider.h", + ], + visibility = ["//visibility:public"], + deps = [], +) + +cc_library( + name = "enum", + srcs = [ + ], + hdrs = [ + "nearby_share_enums.h", + ], + visibility = ["//visibility:public"], + deps = [ + ], +) + +cc_library( + name = "compatible_u8_string", + hdrs = ["compatible_u8_string.h"], + visibility = ["//sharing:__subpackages__"], +) diff --git a/sharing/common/compatible_u8_string.h b/sharing/common/compatible_u8_string.h new file mode 100644 index 00000000..ca9ac276 --- /dev/null +++ b/sharing/common/compatible_u8_string.h @@ -0,0 +1,34 @@ +// Copyright 2024 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_COMPATIBLE_U8_STRING_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_COMPATIBLE_U8_STRING_H_ + +#include + +namespace nearby { +namespace sharing { + +#if defined(__cpp_lib_char8_t) +inline std::string GetCompatibleU8String(std::u8string str) { + return reinterpret_cast(str.c_str()); +} +#else +inline std::string GetCompatibleU8String(std::string str) { return str; } +#endif + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_COMPATIBLE_U8_STRING_H_ diff --git a/sharing/common/fake_nearby_share_profile_info_provider.cc b/sharing/common/fake_nearby_share_profile_info_provider.cc new file mode 100644 index 00000000..97abfec1 --- /dev/null +++ b/sharing/common/fake_nearby_share_profile_info_provider.cc @@ -0,0 +1,40 @@ +// Copyright 2021 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 "sharing/common/fake_nearby_share_profile_info_provider.h" + +#include +#include + +namespace nearby { +namespace sharing { + +FakeNearbyShareProfileInfoProvider::FakeNearbyShareProfileInfoProvider() = + default; + +FakeNearbyShareProfileInfoProvider::~FakeNearbyShareProfileInfoProvider() = + default; + +std::optional FakeNearbyShareProfileInfoProvider::GetGivenName() + const { + return given_name_; +} + +std::optional +FakeNearbyShareProfileInfoProvider::GetProfileUserName() const { + return profile_user_name_; +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/common/fake_nearby_share_profile_info_provider.h b/sharing/common/fake_nearby_share_profile_info_provider.h new file mode 100644 index 00000000..b0f6ec24 --- /dev/null +++ b/sharing/common/fake_nearby_share_profile_info_provider.h @@ -0,0 +1,48 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_FAKE_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_FAKE_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ + +#include +#include + +#include "sharing/common/nearby_share_profile_info_provider.h" + +namespace nearby { +namespace sharing { + +class FakeNearbyShareProfileInfoProvider + : public NearbyShareProfileInfoProvider { + public: + FakeNearbyShareProfileInfoProvider(); + ~FakeNearbyShareProfileInfoProvider() override; + + // NearbyShareProfileInfoProvider: + std::optional GetGivenName() const override; + std::optional GetProfileUserName() const override; + + void set_given_name(const std::optional& given_name) { + given_name_ = given_name; + } + + private: + std::optional given_name_; + std::optional profile_user_name_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_FAKE_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ diff --git a/sharing/common/nearby_share_enums.h b/sharing/common/nearby_share_enums.h new file mode 100644 index 00000000..b17903af --- /dev/null +++ b/sharing/common/nearby_share_enums.h @@ -0,0 +1,114 @@ +// Copyright 2021-2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_ENUMS_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_ENUMS_H_ + +namespace nearby { +namespace sharing { + +// Represents the advertising bluetooth power for Nearby Connections. +enum class PowerLevel { + kUnknown = 0, + kLowPower = 1, + kMediumPower = 2, + kHighPower = 3, + kMaxValue = kHighPower +}; + +enum class DeviceNameValidationResult { + // The device name was valid. + kValid = 0, + // The device name must not be empty. + kErrorEmpty = 1, + // The device name is too long. + kErrorTooLong = 2, + // The device name is not valid UTF-8. + kErrorNotValidUtf8 = 3 +}; + +// Describes the type of device for a ShareTarget. +// The numeric values are used to encode/decode advertisement bytes, and must +// be kept in sync with Android implementation. +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. +enum class ShareTargetType { + // Unknown device type. + kUnknown = 0, + // A phone. + kPhone = 1, + // A tablet. + kTablet = 2, + // A laptop. + kLaptop = 3, +}; + +// This enum combines both text and file share attachment types into a single +// enum that more directly maps to what is shown to the user for preview. +enum class ShareType { + // A generic non-file text share. + kText, + // A text share representing a url, opened in browser. + kUrl, + // A text share representing a phone number, opened in dialer. + kPhone, + // A text share representing an address, opened in browser. + kAddress, + // Multiple files are being shared, we don't capture the specific types. + kMultipleFiles, + // Single file attachment with a mime type of 'image/*'. + kImageFile, + // Single file attachment with a mime type of 'video/*'. + kVideoFile, + // Single file attachment with a mime type of 'audio/*'. + kAudioFile, + // Single file attachment with a mime type of 'application/pdf'. + kPdfFile, + // Single file attachment with a mime type of + // 'application/vnd.google-apps.document'. + kGoogleDocsFile, + // Single file attachment with a mime type of + // 'application/vnd.google-apps.spreadsheet'. + kGoogleSheetsFile, + // Single file attachment with a mime type of + // 'application/vnd.google-apps.presentation'. + kGoogleSlidesFile, + // Single file attachment with mime type of + // 'text/plain' + kTextFile, + // Single file attachment with un-matched mime type. + kUnknownFile, + // Single WiFi credentials attachment. + kWifiCredentials, +}; + +enum class FileSenderType { + kUnknown = 0, + // The user sends files using context menu. + kContextMenu = 1, + // The user sends files using drag and drop. + kDragAndDrop = 2, + // The user sends files by clicking the "Select files" button. + kSelectFilesButton = 3, + // The user sends files by pasting (e.g. ctrl+v) into the Nearby Share app. + kPaste = 4, + // The user sends files by clicking the "Select folders" button. + kSelectFoldersButton = 5, + kMaxValue = kSelectFoldersButton +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_ENUMS_H_ diff --git a/sharing/common/nearby_share_prefs.cc b/sharing/common/nearby_share_prefs.cc new file mode 100644 index 00000000..b395f741 --- /dev/null +++ b/sharing/common/nearby_share_prefs.cc @@ -0,0 +1,177 @@ +// Copyright 2021-2023 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 "sharing/common/nearby_share_prefs.h" + +#include +#include + +#include "absl/time/clock.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/proto/enums.pb.h" + +namespace nearby { +namespace sharing { +namespace prefs { +namespace { +using ::nearby::sharing::api::PreferenceManager; + +using DataUsage = ::nearby::sharing::proto::DataUsage; +using FastInitiationNotificationState = + ::nearby::sharing::proto::FastInitiationNotificationState; +} // namespace + +const char kNearbySharingAllowedContactsName[] = + "nearby_sharing.allowed_contacts"; +const char kNearbySharingBackgroundVisibilityName[] = + "nearby_sharing.background_visibility"; +const char kNearbySharingBackgroundTemporarilyVisibleName[] = + "nearby_sharing.background_temporarily_visible"; +const char kNearbySharingBackgroundFallbackVisibilityName[] = + "nearby_sharing.background_fallback_visibility"; +const char kNearbySharingBackgroundVisibilityExpirationSeconds[] = + "nearby_sharing.background_visibility_expiration_seconds"; +const char kNearbySharingContactUploadHashName[] = + "nearby_sharing.contact_upload_hash"; +const char kNearbySharingCustomSavePath[] = "nearby_sharing.custom_save_path"; +const char kNearbySharingDataUsageName[] = "nearby_sharing.data_usage"; +const char kNearbySharingDeviceIdName[] = "nearby_sharing.device_id"; +const char kNearbySharingDeviceNameName[] = "nearby_sharing.device_name"; +const char kNearbySharingEnabledName[] = "nearby_sharing.enabled"; +const char kNearbySharingFastInitiationNotificationStateName[] = + "nearby_sharing.fast_initiation_notification_state"; +const char kNearbySharingOnboardingCompleteName[] = + "nearby_sharing.onboarding_complete"; +const char kNearbySharingFullNameName[] = "nearby_sharing.full_name"; +const char kNearbySharingIconUrlName[] = "nearby_sharing.icon_url"; +const char kNearbySharingIconTokenName[] = "nearby_sharing.icon_token"; +const char kNearbySharingOnboardingDismissedTimeName[] = + "nearby_sharing.onboarding_dismissed_time"; +const char kNearbySharingPublicCertificateExpirationDictName[] = + "nearbyshare.public_certificate_expiration_dict"; +const char kNearbySharingPrivateCertificateListName[] = + "nearbyshare.private_certificate_list"; +const char kNearbySharingSchedulerContactDownloadAndUploadName[] = + "nearby_sharing.scheduler.contact_download_and_upload"; +const char kNearbySharingSchedulerDownloadDeviceDataName[] = + "nearby_sharing.scheduler.download_device_data"; +const char kNearbySharingSchedulerDownloadPublicCertificatesName[] = + "nearby_sharing.scheduler.download_public_certificates"; +const char kNearbySharingSchedulerPeriodicContactUploadName[] = + "nearby_sharing.scheduler.periodic_contact_upload"; +const char kNearbySharingSchedulerPrivateCertificateExpirationName[] = + "nearby_sharing.scheduler.private_certificate_expiration"; +const char kNearbySharingSchedulerPublicCertificateExpirationName[] = + "nearby_sharing.scheduler.public_certificate_expiration"; +const char kNearbySharingSchedulerUploadDeviceNameName[] = + "nearby_sharing.scheduler.upload_device_name"; +const char kNearbySharingSchedulerUploadLocalDeviceCertificatesName[] = + "nearby_sharing.scheduler.upload_local_device_certificates"; +const char kNearbySharingUsersName[] = "nearby_sharing.users"; +const char kNearbySharingIsReceivingName[] = "nearby_sharing.is_receiving"; +const char kNearbySharingIsAnalyticsEnabledName[] = + "nearby_sharing.is_analytics_enabled"; +const char kNearbySharingIsAllContactsEnabledName[] = + "nearby_sharing.is_all_contacts_enabled"; +const char kNearbySharingAutoAppStartEnabledName[] = + "nearby_sharing.auto_app_start_enabled"; + +void RegisterNearbySharingPrefs(PreferenceManager& preference_manager, + bool skip_persistent_ones) { + // These prefs are not synced across devices on purpose. + + if (!skip_persistent_ones) { + // During logging out, we reset all settings and set these settings to new + // values. To avoid setting them twice, we skip them here if + // skip_persistent_ones is set to true. + preference_manager.SetBoolean(kNearbySharingEnabledName, false); + preference_manager.SetString(kNearbySharingCustomSavePath, std::string()); + preference_manager.SetBoolean(kNearbySharingOnboardingCompleteName, false); + preference_manager.SetInteger(kNearbySharingBackgroundVisibilityName, + static_cast(kDefaultVisibility)); + preference_manager.SetInteger( + kNearbySharingBackgroundFallbackVisibilityName, + static_cast(kDefaultFallbackVisibility)); + preference_manager.SetBoolean(kNearbySharingIsReceivingName, true); + } + + preference_manager.SetInteger( + kNearbySharingFastInitiationNotificationStateName, + /*value=*/static_cast( + FastInitiationNotificationState::ENABLED_FAST_INIT)); + + preference_manager.SetInteger( + kNearbySharingDataUsageName, + static_cast(DataUsage::WIFI_ONLY_DATA_USAGE)); + + preference_manager.SetString(kNearbySharingContactUploadHashName, + std::string()); + + preference_manager.SetString(kNearbySharingDeviceIdName, std::string()); + + preference_manager.SetString(kNearbySharingDeviceNameName, std::string()); + + preference_manager.SetStringArray(kNearbySharingAllowedContactsName, + std::vector()); + + preference_manager.SetString(kNearbySharingFullNameName, std::string()); + + preference_manager.SetString(kNearbySharingIconUrlName, std::string()); + + preference_manager.SetString(kNearbySharingIconTokenName, std::string()); + + preference_manager.SetTime(kNearbySharingOnboardingDismissedTimeName, + absl::Now()); + + preference_manager.Remove(kNearbySharingPublicCertificateExpirationDictName); + preference_manager.Remove(kNearbySharingPrivateCertificateListName); + preference_manager.Remove( + kNearbySharingSchedulerContactDownloadAndUploadName); + preference_manager.Remove(kNearbySharingSchedulerDownloadDeviceDataName); + preference_manager.Remove( + kNearbySharingSchedulerDownloadPublicCertificatesName); + preference_manager.Remove(kNearbySharingSchedulerPeriodicContactUploadName); + preference_manager.Remove( + kNearbySharingSchedulerPrivateCertificateExpirationName); + preference_manager.Remove( + kNearbySharingSchedulerPublicCertificateExpirationName); + preference_manager.Remove(kNearbySharingSchedulerUploadDeviceNameName); + preference_manager.Remove( + kNearbySharingSchedulerUploadLocalDeviceCertificatesName); + preference_manager.Remove(kNearbySharingUsersName); + + preference_manager.SetBoolean(kNearbySharingIsAnalyticsEnabledName, false); + preference_manager.SetBoolean(kNearbySharingIsAllContactsEnabledName, true); + preference_manager.SetBoolean(kNearbySharingAutoAppStartEnabledName, true); +} + +void ResetSchedulers(PreferenceManager& preference_manager) { + preference_manager.Remove( + kNearbySharingSchedulerContactDownloadAndUploadName); + preference_manager.Remove(kNearbySharingSchedulerDownloadDeviceDataName); + preference_manager.Remove( + kNearbySharingSchedulerDownloadPublicCertificatesName); + preference_manager.Remove(kNearbySharingSchedulerPeriodicContactUploadName); + preference_manager.Remove( + kNearbySharingSchedulerPrivateCertificateExpirationName); + preference_manager.Remove( + kNearbySharingSchedulerPublicCertificateExpirationName); + preference_manager.Remove(kNearbySharingSchedulerUploadDeviceNameName); + preference_manager.Remove( + kNearbySharingSchedulerUploadLocalDeviceCertificatesName); +} + +} // namespace prefs +} // namespace sharing +} // namespace nearby diff --git a/sharing/common/nearby_share_prefs.h b/sharing/common/nearby_share_prefs.h new file mode 100644 index 00000000..cafc243c --- /dev/null +++ b/sharing/common/nearby_share_prefs.h @@ -0,0 +1,88 @@ +// Copyright 2021-2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PREFS_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PREFS_H_ + +#include "absl/base/attributes.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/proto/enums.pb.h" + +namespace nearby { +namespace sharing { +namespace prefs { + +ABSL_CONST_INIT extern const char kNearbySharingAllowedContactsName[]; +ABSL_CONST_INIT extern const char kNearbySharingBackgroundVisibilityName[]; +ABSL_CONST_INIT extern const char + kNearbySharingBackgroundTemporarilyVisibleName[]; +ABSL_CONST_INIT extern const char + kNearbySharingBackgroundFallbackVisibilityName[]; +ABSL_CONST_INIT extern const char + kNearbySharingBackgroundVisibilityExpirationSeconds[]; +ABSL_CONST_INIT extern const char kNearbySharingContactUploadHashName[]; +ABSL_CONST_INIT extern const char kNearbySharingCustomSavePath[]; +ABSL_CONST_INIT extern const char kNearbySharingDataUsageName[]; +ABSL_CONST_INIT extern const char kNearbySharingDeviceIdName[]; +ABSL_CONST_INIT extern const char kNearbySharingDeviceNameName[]; +ABSL_CONST_INIT extern const char kNearbySharingEnabledName[]; +ABSL_CONST_INIT extern const char + kNearbySharingFastInitiationNotificationStateName[]; +ABSL_CONST_INIT extern const char kNearbySharingOnboardingCompleteName[]; +ABSL_CONST_INIT extern const char kNearbySharingFullNameName[]; +ABSL_CONST_INIT extern const char kNearbySharingIconUrlName[]; +ABSL_CONST_INIT extern const char kNearbySharingIconTokenName[]; +ABSL_CONST_INIT extern const char kNearbySharingOnboardingDismissedTimeName[]; +ABSL_CONST_INIT extern const char kNearbySharingPrivateCertificateListName[]; +ABSL_CONST_INIT extern const char + kNearbySharingPublicCertificateExpirationDictName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerContactDownloadAndUploadName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerDownloadDeviceDataName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerDownloadPublicCertificatesName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerPeriodicContactUploadName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerPrivateCertificateExpirationName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerPublicCertificateExpirationName[]; +ABSL_CONST_INIT extern const char kNearbySharingSchedulerUploadDeviceNameName[]; +ABSL_CONST_INIT extern const char + kNearbySharingSchedulerUploadLocalDeviceCertificatesName[]; +ABSL_CONST_INIT extern const char kNearbySharingUsersName[]; +ABSL_CONST_INIT extern const char kNearbySharingIsReceivingName[]; +ABSL_CONST_INIT extern const char kNearbySharingIsAnalyticsEnabledName[]; +ABSL_CONST_INIT extern const char kNearbySharingIsAllContactsEnabledName[]; +ABSL_CONST_INIT extern const char kNearbySharingAutoAppStartEnabledName[]; + +ABSL_CONST_INIT const proto::DeviceVisibility kDefaultVisibility = + proto::DeviceVisibility::DEVICE_VISIBILITY_HIDDEN; +ABSL_CONST_INIT const proto::DeviceVisibility kDefaultFallbackVisibility = + proto::DeviceVisibility::DEVICE_VISIBILITY_HIDDEN; +ABSL_CONST_INIT const int kDefaultMaxVisibilityExpirationSeconds = 300; + +void RegisterNearbySharingPrefs( + nearby::sharing::api::PreferenceManager& preference_manager, + bool skip_persistent_ones = false); + +void ResetSchedulers( + nearby::sharing::api::PreferenceManager& preference_manager); + +} // namespace prefs +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PREFS_H_ diff --git a/sharing/common/nearby_share_profile_info_provider.h b/sharing/common/nearby_share_profile_info_provider.h new file mode 100644 index 00000000..0de5feb1 --- /dev/null +++ b/sharing/common/nearby_share_profile_info_provider.h @@ -0,0 +1,39 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ + +#include +#include + +namespace nearby { +namespace sharing { +class NearbyShareProfileInfoProvider { + public: + NearbyShareProfileInfoProvider() = default; + virtual ~NearbyShareProfileInfoProvider() = default; + + // Returns UTF-8 encoded given name of current account. + // Returns absl::nullopt if a valid given name cannot be returned. + virtual std::optional GetGivenName() const = 0; + + // Proxy for Profile::GetProfileUserName(). Returns absl::nullopt if a valid + // username cannot be returned. + virtual std::optional GetProfileUserName() const = 0; +}; +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_PROFILE_INFO_PROVIDER_H_ diff --git a/sharing/common/nearby_share_switches.cc b/sharing/common/nearby_share_switches.cc new file mode 100644 index 00000000..df4ff3a3 --- /dev/null +++ b/sharing/common/nearby_share_switches.cc @@ -0,0 +1,41 @@ +// Copyright 2021 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 "sharing/common/nearby_share_switches.h" + +#include +#include + +namespace nearby { +namespace sharing { +namespace switches { + +int global_host_size = 0; +char global_host[256]; + +void SetNearbySharedHttpHost(const std::string& host) { + if (host.size() > 256) { + return; + } + global_host_size = host.size(); + memcpy(global_host, host.c_str(), global_host_size); +} + +std::string GetNearbySharedHttpHost() { + return std::string(global_host, global_host_size); +} + +} // namespace switches +} // namespace sharing +} // namespace nearby diff --git a/sharing/common/nearby_share_switches.h b/sharing/common/nearby_share_switches.h new file mode 100644 index 00000000..61abfd5f --- /dev/null +++ b/sharing/common/nearby_share_switches.h @@ -0,0 +1,34 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_ +#define THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_ + +#include + +namespace nearby { +namespace sharing { +namespace switches { + +// All switches in alphabetical order. The switches should be documented +// alongside the definition of their values in the .cc file. + +void SetNearbySharedHttpHost(const std::string& host); +std::string GetNearbySharedHttpHost(); + +} // namespace switches +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_COMMON_NEARBY_SHARE_SWITCHES_H_ diff --git a/sharing/internal/api/BUILD b/sharing/internal/api/BUILD new file mode 100644 index 00000000..795111af --- /dev/null +++ b/sharing/internal/api/BUILD @@ -0,0 +1,73 @@ +# Copyright 2023 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. + +licenses(["notice"]) + +cc_library( + name = "platform", + hdrs = [ + "app_info.h", + "bluetooth_adapter.h", + "fast_init_ble_beacon.h", + "fast_initiation_manager.h", + "network_monitor.h", + "preference_manager.h", + "private_certificate_data.h", + "public_certificate_database.h", + "sharing_platform.h", + "shell.h", + "system_info.h", + "wifi_adapter.h", + ], + visibility = [ + "//location/nearby/analytics/cpp/logging:__pkg__", + "//location/nearby/apps/better_together/macos/nearby_share:__subpackages__", + "//location/nearby/cpp/sharing:__subpackages__", + "//sharing:__subpackages__", + ], + deps = [ + "//internal/platform:types", + "//internal/platform/implementation:types", + "//sharing/proto:share_cc_proto", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "mock_sharing_platform", + testonly = True, + hdrs = [ + "mock_app_info.h", + "mock_bluetooth_adapter.h", + "mock_network_monitor.h", + "mock_public_certificate_db.h", + "mock_sharing_platform.h", + "mock_system_info.h", + ], + visibility = ["//visibility:public"], + deps = [ + ":platform", + "//internal/platform:types", + "//internal/platform/implementation:types", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_for_library_testonly", + ], +) diff --git a/sharing/internal/api/app_info.h b/sharing/internal/api/app_info.h new file mode 100644 index 00000000..2efe2c4b --- /dev/null +++ b/sharing/internal/api/app_info.h @@ -0,0 +1,61 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_APP_INFO_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_APP_INFO_H_ + +#include +#include + +namespace nearby { +namespace api { + +// AppInfo provides information about the app, such as version, update track and +// language. +class AppInfo { + public: + virtual ~AppInfo() = default; + + // The current app version, e.g. "1.0.4.2". + virtual std::optional GetAppVersion() = 0; + + // The language the user uses in the app. This should only include the + // language code and not the region code, e.g. "en" NOT "en_US". + virtual std::optional GetAppLanguage() = 0; + + // The track to update the app. + // + // In NearbyShare Windows app, it's from the registry value set by the + // installer, and could be "NearbyManualQA", "NearbyDeveloper", + // "NearbyDogfood". + // + // It's a string instead of enum to provide flexibility so that any new value + // can be recognized without adding the enum value first. + virtual std::optional GetUpdateTrack() = 0; + + // Indicates how the client desktop application was installed on the device, + // e.g. manually installed by the user or OEM preinstall. + virtual std::optional GetAppInstallSource() = 0; + + // Whether the app install event has already been logged. + virtual bool GetFirstRunDone() = 0; + + // Sets whether the app install event has been logged. + virtual bool SetFirstRunDone(bool value) = 0; +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_APP_INFO_H_ diff --git a/sharing/internal/api/bluetooth_adapter.h b/sharing/internal/api/bluetooth_adapter.h new file mode 100644 index 00000000..63527d54 --- /dev/null +++ b/sharing/internal/api/bluetooth_adapter.h @@ -0,0 +1,105 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_BLUETOOTH_ADAPTER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_BLUETOOTH_ADAPTER_H_ + +#include +#include +#include +#include + +namespace nearby { +namespace sharing { +namespace api { + +class BluetoothAdapter { + public: + enum class PermissionStatus { + kUndetermined = 0, + kSystemDenied, + kUserDenied, + kAllowed + }; + + class Observer { + public: + virtual ~Observer() = default; + + // Called when the presence of the adapter |adapter| changes. When |present| + // is true the adapter is now present, false means the adapter has been + // removed from the system. + virtual void AdapterPresentChanged(BluetoothAdapter* adapter, + bool present) {} + + // Called when the radio power state of the adapter |adapter| changes. When + // |powered| is true the adapter radio is powered, false means the adapter + // radio is off. + virtual void AdapterPoweredChanged(BluetoothAdapter* adapter, + bool powered) {} + }; + + virtual ~BluetoothAdapter() = default; + + // Indicates whether the adapter is actually present on the system. An adapter + // is only considered present if the bluetooth mac address has been obtained. + virtual bool IsPresent() const = 0; + + // Indicates whether the adapter radio is powered. + virtual bool IsPowered() const = 0; + + // Indicates whether the adapter supports BLE. + virtual bool IsLowEnergySupported() const = 0; + + // Indicates whether the adapter supports BLE offloads to scan. + virtual bool IsScanOffloadSupported() const = 0; + + // Indicates whether the adapter supports BLE advertisement offload. + virtual bool IsAdvertisementOffloadSupported() const = 0; + + // Indicates whether the adapter supports BLE 5.0 Extended Advertising. + virtual bool IsExtendedAdvertisingSupported() const = 0; + + // Indicates whether the adapter supports BLE Peripheral Role. + virtual bool IsPeripheralRoleSupported() const = 0; + + // Returns the status of the browser's Bluetooth permission status. + virtual PermissionStatus GetOsPermissionStatus() const = 0; + + // Requests a change to the adapter radio power. Setting |powered| to true + // will turn on the radio and false will turn it off. On success, + // |success_callback| will be called. On failure, |error_callback| will be + // called. + virtual void SetPowered(bool powered, std::function success_callback, + std::function error_callback) = 0; + + // The unique ID/name of this adapter. + virtual std::optional GetAdapterId() const = 0; + + // The mac address of this adapter. + virtual std::optional> GetAddress() const = 0; + + // Adds and removes observers for events on this bluetooth adapter. If + // monitoring multiple adapters, check the |adapter| parameter of observer + // methods to determine which adapter is issuing the event. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + virtual bool HasObserver(Observer* observer) = 0; +}; + +} // namespace api +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_BLUETOOTH_ADAPTER_H_ diff --git a/sharing/internal/api/fast_init_ble_beacon.h b/sharing/internal/api/fast_init_ble_beacon.h new file mode 100644 index 00000000..0a578a9d --- /dev/null +++ b/sharing/internal/api/fast_init_ble_beacon.h @@ -0,0 +1,151 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INIT_BLE_BEACON_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INIT_BLE_BEACON_H_ + +#include +#include + +namespace nearby { +namespace api { + +class FastInitBleBeacon { + public: + // Possible types of error raised while registering or unregistering Fast + // Initiation BLE Beacon. + enum class ErrorCode : int { + kUnsupportedPlatform = 0, // BLE Beacon not supported + // on current platform. + kBeaconAlreadyExists, // A BLE Beacon is already + // registered. + kBeaconDoesNotExist, // Unregistering a BLE Beacon which + // is not registered. + kBeaconInvalidLength, // BLE Beacon is not of a valid + // length. + kFailToStartBeacon, // Error when starting the BLE Beacon + // scanning/advertising through a platform API. + kFailToStopBeacon, // Error when stopping the BLE Beacon + // scanning/advertising through a platform API. + kFailToResetBeacon, // Error while resetting BLE Beacon. + kAdapterPoweredOff, // Error because the adapter is off + kUnknown + }; + + enum class FastInitVersion : int { kV1 = 0 }; + + enum class FastInitType : int { kNotify = 0, kSilent = 1 }; + + static constexpr uint8_t kFastInitServiceUuid[] = {0xfe, 0x2c}; + static constexpr uint8_t kFastInitModelId[] = {0xfc, 0x12, 0x8e}; + + // Size of fields in AdvertisingData Service Data (in bytes) + static constexpr uint8_t kFastInitServiceUuidSize = 2; + static constexpr uint8_t kFastInitModelIdSize = 3; + // FastInit V1 Metadata (2 bytes) + // (1 byte) [ version (3 bits) | type (3 bits) | uwb_supported (1 bit) | + // sender_cert_supported (1 bit)] + // (1 byte) [ adjusted_tx_power] + static constexpr uint8_t kUwbMetadataSize = 1; + static constexpr uint8_t kUwbAddressSize = 8; + static constexpr uint8_t kSaltSize = 1; + static constexpr uint8_t kSecretIdHashSize = 8; + + // require_bt_advertising (1 bit) | self_only_advertising (1 bit) | + // unused (6 bits) + static constexpr uint8_t kRequireBtAdvertising = 1; + static constexpr uint8_t kSelfOnlyAdvertising = 1; + + static constexpr uint8_t kAdvertiseDataTotalSize = 26; + + virtual ~FastInitBleBeacon() = default; + + FastInitVersion GetVersion() const { return version_; } + FastInitType GetType() const { return type_; } + bool GetUwbSupported() const { return is_uwb_supported_; } + bool GetSenderCertSupported() const { return is_sender_cert_supported_; } + int8_t GetAdjustedTxPower() const { return adjusted_tx_power_; } + std::array GetUwbMetadata() const { + return uwb_metadata_; + } + std::array GetUwbAddress() const { + return uwb_address_; + } + std::array GetSalt() const { return salt_; } + std::array GetSecretIdHash() const { + return secret_id_hash_; + } + bool GetRequireBtAdvertising() const { return require_bt_advertising_; } + bool GetSelfOnlyAdvertising() const { return self_only_advertising_; } + + void SetVersion(FastInitVersion version) { version_ = version; } + void SetType(FastInitType type) { type_ = type; } + void SetUwbSupported(bool is_supported) { is_uwb_supported_ = is_supported; } + void SetSenderCertSupported(bool is_supported) { + is_sender_cert_supported_ = is_supported; + } + void SetAdjustedTxPower(int8_t signed_value) { + adjusted_tx_power_ = signed_value; + } + void SetUwbMetadata(std::array byte_array) { + uwb_metadata_ = byte_array; + } + void SetUwbAddress(std::array byte_array) { + uwb_address_ = byte_array; + } + void SetSalt(std::array byte_array) { + salt_ = byte_array; + } + void SetSecretIdHash(std::array byte_array) { + secret_id_hash_ = byte_array; + } + + std::array GetAdDataByteArray() { + return advertising_data_byte_array_; + } + void SetAdDataByteArray( + std::array byte_array) { + advertising_data_byte_array_ = byte_array; + } + + void SetRequireBtAdvertising(bool require_bt_advertising) { + require_bt_advertising_ = require_bt_advertising; + } + void SetSelfOnlyAdvertising(bool self_only_advertising) { + self_only_advertising_ = self_only_advertising; + } + + virtual void SerializeToByteArray() = 0; + virtual void ParseFromByteArray() = 0; + + protected: + FastInitVersion version_; + FastInitType type_; + bool is_uwb_supported_; + bool is_sender_cert_supported_; + int8_t adjusted_tx_power_; + std::array uwb_metadata_; + std::array uwb_address_; + std::array salt_; + std::array secret_id_hash_; + bool require_bt_advertising_; + bool self_only_advertising_; + + std::array advertising_data_byte_array_; +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INIT_BLE_BEACON_H_ diff --git a/sharing/internal/api/fast_initiation_manager.h b/sharing/internal/api/fast_initiation_manager.h new file mode 100644 index 00000000..aec7c3be --- /dev/null +++ b/sharing/internal/api/fast_initiation_manager.h @@ -0,0 +1,65 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_ + +#include + +#include "sharing/internal/api/fast_init_ble_beacon.h" + +namespace nearby { +namespace api { + +class FastInitiationManager { + public: + enum class Error : int { + kUnknown = 0, + kBluetoothRadioUnavailable, + kResourceInUse, + kDisabledByPolicy, + kDisabledByUser, + kHardwareNotSupported, + kTransportNotSupported, + kConsentRequired + }; + + FastInitiationManager() = default; + virtual ~FastInitiationManager() = default; + + virtual void StartAdvertising( + api::FastInitBleBeacon::FastInitType type, + std::function callback, + std::function + error_callback) = 0; + + virtual void StopAdvertising(std::function callback) = 0; + + virtual void StartScanning( + std::function devices_discovered_callback, + std::function devices_not_discovered_callback, + std::function + error_callback) = 0; + + virtual void StopScanning(std::function callback) = 0; + + virtual bool IsAdvertising() = 0; + + virtual bool IsScanning() = 0; +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_FAST_INITIATION_MANAGER_H_ diff --git a/sharing/internal/api/mock_app_info.h b/sharing/internal/api/mock_app_info.h new file mode 100644 index 00000000..1d9a5c94 --- /dev/null +++ b/sharing/internal/api/mock_app_info.h @@ -0,0 +1,49 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_APP_INFO_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_APP_INFO_H_ + +#include +#include + +#include "sharing/internal/api/app_info.h" + +#include "gmock/gmock.h" + +namespace nearby::sharing::api { + +class MockAppInfo : public nearby::api::AppInfo { + public: + MockAppInfo() = default; + MockAppInfo(const MockAppInfo&) = delete; + MockAppInfo& operator=(const MockAppInfo&) = delete; + ~MockAppInfo() override = default; + + MOCK_METHOD(std::optional, GetAppVersion, (), (override)); + + MOCK_METHOD(std::optional, GetAppLanguage, (), (override)); + + MOCK_METHOD(std::optional, GetUpdateTrack, (), (override)); + + MOCK_METHOD(std::optional, GetAppInstallSource, (), (override)); + + MOCK_METHOD(bool, GetFirstRunDone, (), (override)); + + MOCK_METHOD(bool, SetFirstRunDone, (bool value), (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_APP_INFO_H_ diff --git a/sharing/internal/api/mock_bluetooth_adapter.h b/sharing/internal/api/mock_bluetooth_adapter.h new file mode 100644 index 00000000..66cce74f --- /dev/null +++ b/sharing/internal/api/mock_bluetooth_adapter.h @@ -0,0 +1,58 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_BLUETOOTH_ADAPTER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_BLUETOOTH_ADAPTER_H_ + +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "sharing/internal/api/bluetooth_adapter.h" + +namespace nearby::sharing::api { + +class MockBluetoothAdapter : public nearby::sharing::api::BluetoothAdapter { + public: + MockBluetoothAdapter() = default; + MockBluetoothAdapter(const MockBluetoothAdapter&) = delete; + MockBluetoothAdapter& operator=(const MockBluetoothAdapter&) = delete; + ~MockBluetoothAdapter() override = default; + + MOCK_METHOD(bool, IsPresent, (), (const, override)); + MOCK_METHOD(bool, IsPowered, (), (const, override)); + MOCK_METHOD(bool, IsLowEnergySupported, (), (const, override)); + MOCK_METHOD(bool, IsScanOffloadSupported, (), (const, override)); + MOCK_METHOD(bool, IsAdvertisementOffloadSupported, (), (const, override)); + MOCK_METHOD(bool, IsExtendedAdvertisingSupported, (), (const, override)); + MOCK_METHOD(bool, IsPeripheralRoleSupported, (), (const, override)); + MOCK_METHOD(PermissionStatus, GetOsPermissionStatus, (), (const, override)); + MOCK_METHOD(void, SetPowered, + (bool powered, std::function success_callback, + std::function error_callback), + (override)); + MOCK_METHOD(std::optional, GetAdapterId, (), (const, override)); + MOCK_METHOD((std::optional>), GetAddress, (), + (const, override)); + MOCK_METHOD(void, AddObserver, (Observer * observer), (override)); + MOCK_METHOD(void, RemoveObserver, (Observer * observer), (override)); + MOCK_METHOD(bool, HasObserver, (Observer * observer), (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_BLUETOOTH_ADAPTER_H_ diff --git a/sharing/internal/api/mock_network_monitor.h b/sharing/internal/api/mock_network_monitor.h new file mode 100644 index 00000000..5a2ca490 --- /dev/null +++ b/sharing/internal/api/mock_network_monitor.h @@ -0,0 +1,38 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_NETWORK_MONITOR_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_NETWORK_MONITOR_H_ + +#include "sharing/internal/api/network_monitor.h" + +#include "gmock/gmock.h" + +namespace nearby::sharing::api { + +class MockNetworkMonitor : public nearby::api::NetworkMonitor { + public: + MockNetworkMonitor() : nearby::api::NetworkMonitor(nullptr) {} + MockNetworkMonitor(const MockNetworkMonitor&) = delete; + MockNetworkMonitor& operator=(const MockNetworkMonitor&) = delete; + ~MockNetworkMonitor() override = default; + + MOCK_METHOD(bool, IsLanConnected, (), (override)); + + MOCK_METHOD(ConnectionType, GetCurrentConnection, (), (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_NETWORK_MONITOR_H_ diff --git a/sharing/internal/api/mock_public_certificate_db.h b/sharing/internal/api/mock_public_certificate_db.h new file mode 100644 index 00000000..e289ce54 --- /dev/null +++ b/sharing/internal/api/mock_public_certificate_db.h @@ -0,0 +1,59 @@ +// Copyright 2024 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_PUBLIC_CERTIFICATE_DB_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_PUBLIC_CERTIFICATE_DB_H_ + +#include +#include +#include + +#include "gmock/gmock.h" +#include "absl/functional/any_invocable.h" +#include "absl/types/span.h" +#include "sharing/internal/api/public_certificate_database.h" + +namespace nearby::sharing::api { +class MockPublicCertificateDb : public PublicCertificateDatabase { + public: + MockPublicCertificateDb() = default; + MockPublicCertificateDb(const PublicCertificateDatabase&) = delete; + MockPublicCertificateDb& operator=(const PublicCertificateDatabase&) = delete; + ~MockPublicCertificateDb() override = default; + + MOCK_METHOD(void, Initialize, + (absl::AnyInvocable callback), (override)); + MOCK_METHOD( + void, LoadEntries, + (absl::AnyInvocable< + void(bool, std::unique_ptr>) &&> + callback), + (override)); + MOCK_METHOD( + void, AddCertificates, + (absl::Span certificates, + absl::AnyInvocable callback), + (override)); + MOCK_METHOD(void, RemoveCertificatesById, + (std::vector ids_to_remove, + absl::AnyInvocable callback), + (override)); + MOCK_METHOD(void, Destroy, (absl::AnyInvocable callback), + (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_PUBLIC_CERTIFICATE_DB_H_ diff --git a/sharing/internal/api/mock_sharing_platform.h b/sharing/internal/api/mock_sharing_platform.h new file mode 100644 index 00000000..d9159e16 --- /dev/null +++ b/sharing/internal/api/mock_sharing_platform.h @@ -0,0 +1,100 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SHARING_PLATFORM_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SHARING_PLATFORM_H_ + +#include +#include + +#include "gmock/gmock.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/platform/device_info.h" +#include "internal/platform/implementation/account_manager.h" +#include "internal/platform/task_runner.h" +#include "sharing/internal/api/app_info.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_init_ble_beacon.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/network_monitor.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/api/public_certificate_database.h" +#include "sharing/internal/api/sharing_platform.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/system_info.h" +#include "sharing/internal/api/wifi_adapter.h" + +namespace nearby::sharing::api { + +class MockSharingPlatform : public SharingPlatform { + public: + MockSharingPlatform() = default; + MockSharingPlatform(const MockSharingPlatform&) = delete; + MockSharingPlatform& operator=(const MockSharingPlatform&) = delete; + ~MockSharingPlatform() override = default; + + MOCK_METHOD(void, InitLogging, (), (override)); + + MOCK_METHOD(void, UpdateLoggingLevel, (), (override)); + + MOCK_METHOD( + std::unique_ptr, CreateNetworkMonitor, + (std::function + callback), + (override)); + + MOCK_METHOD(nearby::sharing::api::BluetoothAdapter&, GetBluetoothAdapter, (), + (override)); + + MOCK_METHOD(nearby::sharing::api::WifiAdapter&, GetWifiAdapter, (), + (override)); + + MOCK_METHOD(void, LaunchDefaultBrowserFromURL, + (absl::string_view url, + std::function callback), + (override)); + + MOCK_METHOD(nearby::api::Shell&, GetShell, (), (override)); + + MOCK_METHOD(nearby::api::FastInitBleBeacon&, GetFastInitBleBeacon, (), + (override)); + + MOCK_METHOD(nearby::api::FastInitiationManager&, GetFastInitiationManager, (), + (override)); + + MOCK_METHOD(void, CopyText, + (absl::string_view text, + std::function callback), + (override)); + + MOCK_METHOD(std::unique_ptr, CreateSystemInfo, (), + (override)); + + MOCK_METHOD(std::unique_ptr, CreateAppInfo, (), + (override)); + + MOCK_METHOD(PreferenceManager&, GetPreferenceManager, (), (override)); + + MOCK_METHOD(AccountManager&, GetAccountManager, (), (override)); + MOCK_METHOD(TaskRunner&, GetDefaultTaskRunner, (), (override)); + MOCK_METHOD(nearby::DeviceInfo&, GetDeviceInfo, (), (override)); + MOCK_METHOD(std::unique_ptr, + CreatePublicCertificateDatabase, + (absl::string_view database_path), (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SHARING_PLATFORM_H_ diff --git a/sharing/internal/api/mock_system_info.h b/sharing/internal/api/mock_system_info.h new file mode 100644 index 00000000..6c6a6b98 --- /dev/null +++ b/sharing/internal/api/mock_system_info.h @@ -0,0 +1,66 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SYSTEM_INFO_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SYSTEM_INFO_H_ + +#include +#include +#include + +#include "gmock/gmock.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/api/system_info.h" + +namespace nearby::sharing::api { + +class MockSystemInfo : public nearby::api::SystemInfo { + public: + MockSystemInfo() = default; + MockSystemInfo(const MockSystemInfo&) = delete; + MockSystemInfo& operator=(const MockSystemInfo&) = delete; + ~MockSystemInfo() override = default; + + MOCK_METHOD(std::string, GetComputerManufacturer, (), (override)); + MOCK_METHOD(std::string, GetComputerModel, (), (override)); + MOCK_METHOD(int64_t, GetComputerPhysicalMemory, (), (override)); + MOCK_METHOD(int, GetComputerProcessorCount, (), (override)); + MOCK_METHOD(int, GetComputerLogicProcessorCount, (), (override)); + MOCK_METHOD(int, GetProcessorMemoryInfo, (), (override)); + + MOCK_METHOD(BatteryChargeStatus, QueryBatteryInfo, + (int& seconds, int& percent, bool& battery_saver), (override)); + + // Operating system related information. + MOCK_METHOD(std::string, GetOsManufacturer, (), (override)); + MOCK_METHOD(std::string, GetOsName, (), (override)); + MOCK_METHOD(std::string, GetOsVersion, (), (override)); + MOCK_METHOD(std::string, GetOsArchitecture, (), (override)); + MOCK_METHOD(std::string, GetOsLanguage, (), (override)); + + // CPU related information. + MOCK_METHOD(std::string, GetProcessorManufacturer, (), (override)); + MOCK_METHOD(std::string, GetProcessorName, (), (override)); + + // Driver related information. + MOCK_METHOD(std::list, GetBluetoothDriverInfos, (), (override)); + MOCK_METHOD(std::list, GetNetworkDriverInfos, (), (override)); + + MOCK_METHOD(void, GetBatteryUsageReport, (absl::string_view save_path), + (override)); +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_MOCK_SYSTEM_INFO_H_ diff --git a/sharing/internal/api/network_monitor.h b/sharing/internal/api/network_monitor.h new file mode 100644 index 00000000..bf0e45aa --- /dev/null +++ b/sharing/internal/api/network_monitor.h @@ -0,0 +1,61 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_NETWORK_MONITOR_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_NETWORK_MONITOR_H_ + +#include +#include +#include + +namespace nearby { +namespace api { + +class NetworkMonitor { + public: + enum class ConnectionType : int { + kUnknown = 0, // A connection exists, but its type is unknown. + // Also used as a default value. + kEthernet = 1, + kWifi = 2, + k2G = 3, + k3G = 4, + k4G = 5, + kNone = 6, // No connection. + kBluetooth = 7, + k5G = 8, + kLast = k5G + }; + + explicit NetworkMonitor(std::function callback) { + callback_ = std::move(callback); + } + + virtual ~NetworkMonitor() = default; + + // Returns true if connected to an AP (Access Point), not necessarily + // connected to the internet + virtual bool IsLanConnected() = 0; + + // Returns the type of connection used currently to access the internet + virtual ConnectionType GetCurrentConnection() = 0; + + protected: + std::function callback_; +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_NETWORK_MONITOR_H_ diff --git a/sharing/internal/api/preference_manager.h b/sharing/internal/api/preference_manager.h new file mode 100644 index 00000000..c15d57bb --- /dev/null +++ b/sharing/internal/api/preference_manager.h @@ -0,0 +1,132 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PREFERENCE_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PREFERENCE_MANAGER_H_ + +#include +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "sharing/internal/api/private_certificate_data.h" + +namespace nearby::sharing::api { + +class PreferenceManager { + public: + virtual ~PreferenceManager() = default; + + virtual void SetBoolean(absl::string_view key, bool value) = 0; + virtual void SetInteger(absl::string_view key, int value) = 0; + virtual void SetInt64(absl::string_view key, int64_t value) = 0; + virtual void SetString(absl::string_view key, absl::string_view value) = 0; + virtual void SetTime(absl::string_view key, absl::Time value) = 0; + + // Array operations, where key contains an array. + virtual void SetBooleanArray(absl::string_view key, + absl::Span value) = 0; + virtual void SetIntegerArray(absl::string_view key, + absl::Span value) = 0; + virtual void SetInt64Array(absl::string_view key, + absl::Span value) = 0; + virtual void SetStringArray(absl::string_view key, + absl::Span value) = 0; + virtual void SetPrivateCertificateArray( + absl::string_view key, + absl::Span value) = 0; + // Expiration data is a std::pair containing the certificate ID base64 encoded + // according to RFC 4648 section 5 and the expiration time in nanos since Unix + // Epoch. + virtual void SetCertificateExpirationArray( + absl::string_view key, + absl::Span> value) = 0; + + // Dictionary operations, where key contains a dictionary, and dictionary_item + // is modified. + // If key is empty, a new dictionary containing the new dictionary_item is + // created. + // If key exists and does not contain a dictionary, the operation fails + // silently. + virtual void SetDictionaryBooleanValue(absl::string_view key, + absl::string_view dictionary_item, + bool value) = 0; + virtual void SetDictionaryIntegerValue(absl::string_view key, + absl::string_view dictionary_item, + int value) = 0; + virtual void SetDictionaryInt64Value(absl::string_view key, + absl::string_view dictionary_item, + int64_t value) = 0; + virtual void SetDictionaryStringValue(absl::string_view key, + absl::string_view dictionary_item, + std::string value) = 0; + virtual void RemoveDictionaryItem(absl::string_view key, + absl::string_view dictionary_item) = 0; + // Gets values + virtual bool GetBoolean(absl::string_view key, bool default_value) const = 0; + virtual int GetInteger(absl::string_view key, int default_value) const = 0; + virtual int64_t GetInt64(absl::string_view key, + int64_t default_value) const = 0; + virtual std::string GetString(absl::string_view key, + const std::string& default_value) const = 0; + virtual absl::Time GetTime(absl::string_view key, + absl::Time default_value) const = 0; + + virtual std::vector GetBooleanArray( + absl::string_view key, absl::Span default_value) const = 0; + virtual std::vector GetIntegerArray( + absl::string_view key, absl::Span default_value) const = 0; + virtual std::vector GetInt64Array( + absl::string_view key, absl::Span default_value) const = 0; + virtual std::vector GetStringArray( + absl::string_view key, + absl::Span default_value) const = 0; + virtual std::vector GetPrivateCertificateArray( + absl::string_view key) const = 0; + // Expiration data is a std::pair containing the certificate ID base64 encoded + // according to RFC 4648 section 5 and the expiration time in nanos since Unix + // Epoch. + virtual std::vector> + GetCertificateExpirationArray(absl::string_view key) const = 0; + + // Dictionary operations, where key contains a dictionary. + // If key does not exist, does not contain a dictionary, or the dictionary + // does not contain dictionary_item, std::nullopt is returned. + virtual std::optional GetDictionaryBooleanValue( + absl::string_view key, absl::string_view dictionary_item) const = 0; + virtual std::optional GetDictionaryIntegerValue( + absl::string_view key, absl::string_view dictionary_item) const = 0; + virtual std::optional GetDictionaryInt64Value( + absl::string_view key, absl::string_view dictionary_item) const = 0; + virtual std::optional GetDictionaryStringValue( + absl::string_view key, absl::string_view dictionary_item) const = 0; + + // Removes preferences + virtual void Remove(absl::string_view key) = 0; + + // Adds preference observer + virtual void AddObserver( + absl::string_view name, + std::function observer) = 0; + virtual void RemoveObserver(absl::string_view name) = 0; +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PREFERENCE_MANAGER_H_ diff --git a/sharing/internal/api/private_certificate_data.h b/sharing/internal/api/private_certificate_data.h new file mode 100644 index 00000000..9a18ff2c --- /dev/null +++ b/sharing/internal/api/private_certificate_data.h @@ -0,0 +1,75 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PRIVATE_CERTIFICATE_DATA_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PRIVATE_CERTIFICATE_DATA_H_ + +#include +#include + +namespace nearby::sharing::api { + +// Intermediate data structure for serializing NearbySharePrivateCertificate +// into preference storage. +struct PrivateCertificateData { + // Dictionary keys used in serialization to and from JSON. + static inline constexpr char kVisibility[] = "visibility"; + static inline constexpr char kNotBefore[] = "not_before"; + static inline constexpr char kNotAfter[] = "not_after"; + static inline constexpr char kKeyPair[] = "key_pair"; + static inline constexpr char kSecretKey[] = "secret_key"; + static inline constexpr char kMetadataEncryptionKey[] = + "metadata_encryption_key"; + static inline constexpr char kId[] = "id"; + static inline constexpr char kUnencryptedMetadata[] = "unencrypted_metadata"; + static inline constexpr char kConsumedSalts[] = "consumed_salts"; + + // One of the DeviceVisibility values. + int visibility; + // Not before time in nanos since Unix epoch + int64_t not_before; + // Not after time in nanos since Unix epoch + int64_t not_after; + // Private key in PKCS #8 PrivateKeyInfo block base64 encoded according to + // RFC 4648 section 5. + std::string key_pair; + // Secret key base64 encoded according to RFC 4648 section 5. + std::string secret_key; + // Metadata encryption key base64 encoded according to RFC 4648 section 5. + std::string metadata_encryption_key; + // Certificate ID base64 encoded according to RFC 4648 section 5. + std::string id; + // Serialized clear text metadata proto base64 encoded according to RFC 4648 + // section 5. + std::string unencrypted_metadata_proto; + // Concatenation of hex encoded 2byte salt values that have already been used. + std::string consumed_salts; +}; + +inline bool operator==(const PrivateCertificateData& lhs, + const PrivateCertificateData& rhs) { + return lhs.visibility == rhs.visibility && + lhs.not_before == rhs.not_before && + lhs.not_after == rhs.not_after && + lhs.key_pair == rhs.key_pair && + lhs.secret_key == rhs.secret_key && + lhs.metadata_encryption_key == rhs.metadata_encryption_key && + lhs.id == rhs.id && + lhs.unencrypted_metadata_proto == rhs.unencrypted_metadata_proto && + lhs.consumed_salts == rhs.consumed_salts; +} + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PRIVATE_CERTIFICATE_DATA_H_ diff --git a/sharing/internal/api/public_certificate_database.h b/sharing/internal/api/public_certificate_database.h new file mode 100644 index 00000000..4c6b0e51 --- /dev/null +++ b/sharing/internal/api/public_certificate_database.h @@ -0,0 +1,76 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PUBLIC_CERTIFICATE_DATABASE_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PUBLIC_CERTIFICATE_DATABASE_H_ + +#include +#include +#include + +#include "absl/functional/any_invocable.h" +#include "absl/types/span.h" +#include "sharing/proto/rpc_resources.pb.h" + +namespace nearby::sharing::api { + +class PublicCertificateDatabase { + public: + enum class InitStatus { + // Initialization successful. + kOk = 0, + // Failed to create database. + kError = 1, + // Existing database files are corrupt. Caller should delete the database + // and try to create it again. + kCorrupt = 2, + }; + + PublicCertificateDatabase() = default; + virtual ~PublicCertificateDatabase() = default; + + // Asynchronously initializes the object, which must have been created by the + // DataManager::GetDataSet function. |callback| can be invoked on an + // executor thread when complete. + virtual void Initialize(absl::AnyInvocable callback) = 0; + + // Asynchronously loads all entries from the database and invokes |callback| + // when complete. + virtual void LoadEntries( + absl::AnyInvocable< + void(bool, std::unique_ptr>) &&> + callback) = 0; + + // Asynchronously saves |certificates| to the database. + // |callback| can be invoked on an executor thread when complete. + virtual void AddCertificates( + absl::Span certificates, + absl::AnyInvocable callback) = 0; + + // Asynchronously deletes certificates with IDs in |ids_to_remove| from the + // database. + // |callback| can be invoked on an executor thread when complete. + virtual void RemoveCertificatesById( + std::vector ids_to_remove, + absl::AnyInvocable callback) = 0; + + // Asynchronously destroys the database. Use this call only if the database + // needs to be destroyed for this particular profile. + virtual void Destroy(absl::AnyInvocable callback) = 0; +}; + +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_PUBLIC_CERTIFICATE_DATABASE_H_ diff --git a/sharing/internal/api/sharing_platform.h b/sharing/internal/api/sharing_platform.h new file mode 100644 index 00000000..2deebb23 --- /dev/null +++ b/sharing/internal/api/sharing_platform.h @@ -0,0 +1,96 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHARING_PLATFORM_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHARING_PLATFORM_H_ + +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/platform/device_info.h" +#include "internal/platform/implementation/account_manager.h" +#include "internal/platform/task_runner.h" +#include "sharing/internal/api/app_info.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_init_ble_beacon.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/network_monitor.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/api/public_certificate_database.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/system_info.h" +#include "sharing/internal/api/wifi_adapter.h" + +namespace nearby::sharing::api { + +constexpr char kSharingPreferencesFilePath[] = "Google/Nearby/Sharing"; + +// Platform abstraction interface for NearbyShare cross-platform compatibility. +class SharingPlatform { + public: + virtual ~SharingPlatform() = default; + + // This function should only be called once. + virtual void InitLogging() = 0; + + // Platform specific implementation to set default logging levels. + virtual void UpdateLoggingLevel() = 0; + + virtual std::unique_ptr CreateNetworkMonitor( + std::function + callback) = 0; + + virtual BluetoothAdapter& GetBluetoothAdapter() = 0; + + virtual WifiAdapter& GetWifiAdapter() = 0; + + virtual void LaunchDefaultBrowserFromURL( + absl::string_view url, std::function callback) = 0; + + virtual nearby::api::Shell& GetShell() = 0; + + virtual nearby::api::FastInitBleBeacon& GetFastInitBleBeacon() = 0; + + virtual nearby::api::FastInitiationManager& GetFastInitiationManager() = 0; + + // Make calls to OS to copy text to clipboard + // + // @param text is a text to copy to clipboard. + // @param callback + // + // If it is successfully copied, callback provided is executed with + // absl::OkStatus. Otherwise, absl::InternalError. + virtual void CopyText(absl::string_view text, + std::function callback) = 0; + + // Creates system information class. SystemInfo provides APIs to access + // system information. + virtual std::unique_ptr CreateSystemInfo() = 0; + + // Creates app information class. AppInfo provides APIs to access app + // information, such as app version. + virtual std::unique_ptr CreateAppInfo() = 0; + + virtual PreferenceManager& GetPreferenceManager() = 0; + virtual AccountManager& GetAccountManager() = 0; + virtual TaskRunner& GetDefaultTaskRunner() = 0; + virtual nearby::DeviceInfo& GetDeviceInfo() = 0; + virtual std::unique_ptr + CreatePublicCertificateDatabase(absl::string_view database_path) = 0; +}; +} // namespace nearby::sharing::api + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHARING_PLATFORM_H_ diff --git a/sharing/internal/api/shell.h b/sharing/internal/api/shell.h new file mode 100644 index 00000000..0934fa61 --- /dev/null +++ b/sharing/internal/api/shell.h @@ -0,0 +1,43 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHELL_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHELL_H_ + +#include // NOLINT(build/c++17) +#include + +#include "absl/status/status.h" + +namespace nearby { +namespace api { + +// Shell defines interfaces to interact with platform core features. +class Shell { + public: + virtual ~Shell() = default; + + // Opens the |path| file or folder with default application. if |path| + // is a directory, will open the folder by explore, otherwise it will + // try to open the file with application supports it. |callback| is called + // when the open operation completed, and absl::StatusCodes::kOk returned + // only when open the path successfully. + virtual void Open(const std::filesystem::path& path, + std::function callback) = 0; +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SHELL_H_ diff --git a/sharing/internal/api/system_info.h b/sharing/internal/api/system_info.h new file mode 100644 index 00000000..638f1068 --- /dev/null +++ b/sharing/internal/api/system_info.h @@ -0,0 +1,183 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SYSTEM_INFO_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SYSTEM_INFO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" + +namespace nearby { +namespace api { + +// SystemInfo provides information about the current computer system, such as +// CPU, memory, OS, driver and configuration information. SystemInfo doesn't +// include specific user information. +class SystemInfo { + public: + typedef struct _DriverInfo { + std::string manufacturer; + std::string device_name; + std::string driver_provider_name; + std::string driver_version; + std::string driver_date; + } DriverInfo; + + enum class BatteryChargeStatus { + UNKNOWN = 0, + NO_BATTERY, + CHARGING, + CHARGED, + ON_BATTERY + }; + + virtual ~SystemInfo() = default; + + // Computer related information. + virtual std::string GetComputerManufacturer() = 0; + virtual std::string GetComputerModel() = 0; + virtual int64_t GetComputerPhysicalMemory() = 0; + virtual int GetComputerProcessorCount() = 0; + virtual int GetComputerLogicProcessorCount() = 0; + virtual int GetProcessorMemoryInfo() = 0; + + virtual BatteryChargeStatus QueryBatteryInfo(int& seconds, int& percent, + bool& battery_saver) = 0; + + // Operating system related information. + virtual std::string GetOsManufacturer() = 0; + virtual std::string GetOsName() = 0; + virtual std::string GetOsVersion() = 0; + virtual std::string GetOsArchitecture() = 0; + virtual std::string GetOsLanguage() = 0; + + // CPU related information. + virtual std::string GetProcessorManufacturer() = 0; + virtual std::string GetProcessorName() = 0; + + // Driver related information. + virtual std::list GetBluetoothDriverInfos() = 0; + virtual std::list GetNetworkDriverInfos() = 0; + + virtual void GetBatteryUsageReport(absl::string_view save_path) = 0; + + // Outputs all system information to a readable string. + std::string Dump() { + std::ostringstream oss; + oss << "System Information" << std::endl; + oss << " Manufacturer: " << GetComputerManufacturer() << std::endl + << " Model: " << GetComputerModel() << std::endl + << " Physical Memory: " << GetComputerPhysicalMemory() << std::endl + << " Processor Count: " << GetComputerProcessorCount() << std::endl + << " Logic Processor Count: " << GetComputerLogicProcessorCount() + << std::endl + << " OS Manufacturer: " << GetOsManufacturer() << std::endl + << " OS Name: " << GetOsName() << std::endl + << " OS Version: " << GetOsVersion() << std::endl + << " OS Architecture: " << GetOsArchitecture() << std::endl + << " OS Language: " << GetOsLanguage() << std::endl + << " CPU Manufacturer: " << GetProcessorManufacturer() << std::endl + << " CPU Name: " << GetProcessorName() << std::endl; + + oss << std::endl; + std::optional> bluetooth_drivers = + GetBluetoothDriverInfos(); + if (bluetooth_drivers.has_value()) { + oss << " Bluetooth Driver Information:" << std::endl; + for (const DriverInfo& driver_info : *bluetooth_drivers) { + oss << " Manufacturer: " << driver_info.manufacturer << std::endl + << " Device Name: " << driver_info.device_name << std::endl + << " Driver Provider Name: " << driver_info.driver_provider_name + << std::endl + << " Driver Version: " << driver_info.driver_version << std::endl + << " Driver Date: " << driver_info.driver_date << std::endl; + } + } else { + oss << " No Bluetooth Driver Information." << std::endl; + } + + oss << std::endl; + std::optional> network_drivers = + GetNetworkDriverInfos(); + if (network_drivers.has_value()) { + oss << " Network Driver Information:" << std::endl; + for (const DriverInfo& driver_info : *network_drivers) { + oss << " Manufacturer: " << driver_info.manufacturer << std::endl + << " Device Name: " << driver_info.device_name << std::endl + << " Driver Provider Name: " << driver_info.driver_provider_name + << std::endl + << " Driver Version: " << driver_info.driver_version << std::endl + << " Driver Date: " << driver_info.driver_date << std::endl; + } + } else { + oss << " No Network Driver Information." << std::endl; + } + + oss << std::endl; + int seconds = 0, percentage = 0; + bool battery_saver = false; + BatteryChargeStatus battery_charge_status = + QueryBatteryInfo(seconds, percentage, battery_saver); + if (battery_charge_status == BatteryChargeStatus::UNKNOWN || + battery_charge_status == BatteryChargeStatus::NO_BATTERY) { + oss << " Computer Battery Information: UNKNOWN or NO_BATTERY" + << std::endl; + } else { + oss << " Computer Battery Information:" << std::endl; + oss << " Power State: " + << BatteryChargeStatusToString(battery_charge_status) << std::endl + << " Battery Percentage: " << percentage << std::endl + << " Battery Left (Seconds): " << seconds << std::endl + << " Battery Saver: " << battery_saver << std::endl; + } + + oss << std::endl; + oss << " Current Process Information:" << std::endl; + oss << " Physical Memory currently in use: " << std::fixed + << std::setprecision(2) + << GetProcessorMemoryInfo() / static_cast(1024 * 1024) << "MB" + << std::endl; + + return oss.str(); + } + + private: + std::string BatteryChargeStatusToString(const BatteryChargeStatus state) { + switch (state) { + case BatteryChargeStatus::NO_BATTERY: + return "NO_BATTERY"; + case BatteryChargeStatus::CHARGING: + return "CHARGING"; + case BatteryChargeStatus::CHARGED: + return "CHARGED"; + case BatteryChargeStatus::ON_BATTERY: + return "ON_BATTERY"; + default: + return "UNKNOWN"; + } + } +}; + +} // namespace api +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_SYSTEM_INFO_H_ diff --git a/sharing/internal/api/wifi_adapter.h b/sharing/internal/api/wifi_adapter.h new file mode 100644 index 00000000..2f7aa680 --- /dev/null +++ b/sharing/internal/api/wifi_adapter.h @@ -0,0 +1,91 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_WIFI_ADAPTER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_WIFI_ADAPTER_H_ + +#include +#include +#include +#include + +#include "absl/status/status.h" + +namespace nearby { +namespace sharing { +namespace api { + +class WifiAdapter { + public: + enum class PermissionStatus { + kUndetermined = 0, + kSystemDenied, + kUserDenied, + kAllowed + }; + + class Observer { + public: + virtual ~Observer() = default; + + // Called when the presence of the adapter `adapter` changes. When `present` + // is true the adapter is now present, false means the adapter has been + // removed from the system. + virtual void AdapterPresentChanged(WifiAdapter* adapter, bool present) {} + + // Called when the radio power state of the adapter `adapter` changes. When + // `powered` is true the adapter radio is powered, false means the adapter + // radio is off. + virtual void AdapterPoweredChanged(WifiAdapter* adapter, bool powered) {} + }; + + virtual ~WifiAdapter() = default; + + // Indicates whether the adapter is actually present/not disabled by the + // device firmware or hardware switch on the system. + virtual bool IsPresent() const = 0; + + // Indicates whether the adapter radio is powered. + virtual bool IsPowered() const = 0; + + // Returns the status of the browser's Wi-Fi permission status. + virtual PermissionStatus GetOsPermissionStatus() const = 0; + + // Requests a change to the adapter radio power. Setting `powered` to true + // will turn on the radio and false will turn it off. On success, + // `success_callback` will be called. On failure, `error_callback` will be + // called. + virtual void SetPowered(bool powered, std::function success_callback, + std::function error_callback) = 0; + + // The unique ID/name of this adapter. + virtual std::optional GetAdapterId() const = 0; + + // Adds and removes observers for events on this Wi-Fi adapter. If + // monitoring multiple adapters, check the `adapter` parameter of observer + // methods to determine which adapter is issuing the event. + virtual void AddObserver(Observer* observer) = 0; + virtual void RemoveObserver(Observer* observer) = 0; + virtual bool HasObserver(Observer* observer) = 0; + + // Requests to join a Wi-Fi network. + virtual void JoinNetwork(absl::string_view ssid, absl::string_view password, + std::function callback) = 0; +}; + +} // namespace api +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_API_WIFI_ADAPTER_H_ diff --git a/sharing/internal/public/BUILD b/sharing/internal/public/BUILD new file mode 100644 index 00000000..24cc9c1c --- /dev/null +++ b/sharing/internal/public/BUILD @@ -0,0 +1,84 @@ +# Copyright 2023 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. + +licenses(["notice"]) + +cc_library( + name = "types", + hdrs = [ + "connectivity_manager.h", + "context.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//internal/network:types", + "//internal/platform:types", + "//sharing/internal/api:platform", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + ], +) + +cc_library( + name = "nearby_context", + srcs = [ + "connectivity_manager_impl.cc", + "context_impl.cc", + ], + hdrs = [ + "connectivity_manager_impl.h", + "context_impl.h", + ], + visibility = ["//visibility:public"], + deps = [ + ":logging", + ":types", + "//internal/network:types", + "//internal/platform:types", + "//sharing/internal/api:platform", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "nearby_context_test", + size = "small", + timeout = "short", + srcs = [ + "connectivity_manager_impl_test.cc", + ], + shard_count = 8, + deps = [ + ":nearby_context", + ":types", + "//internal/platform/implementation/g3", # fixdeps: keep + "//sharing/internal/api:mock_sharing_platform", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "logging", + hdrs = [ + "logging.h", + ], + visibility = ["//visibility:public"], + deps = [ + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + ], +) diff --git a/sharing/internal/public/connectivity_manager.h b/sharing/internal/public/connectivity_manager.h new file mode 100644 index 00000000..8e697e26 --- /dev/null +++ b/sharing/internal/public/connectivity_manager.h @@ -0,0 +1,55 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_H_ + +#include + +#include "absl/strings/string_view.h" + +namespace nearby { + +class ConnectivityManager { + public: + enum class ConnectionType { + kUnknown = 0, // A connection exists, but its type is unknown. + // Also used as a default value. + kEthernet = 1, + kWifi = 2, + k2G = 3, + k3G = 4, + k4G = 5, + kNone = 6, // No connection. + kBluetooth = 7, + k5G = 8, + kLast = k5G + }; + + virtual ~ConnectivityManager() = default; + + virtual bool IsLanConnected() = 0; + + virtual ConnectionType GetConnectionType() = 0; + + virtual void RegisterConnectionListener( + absl::string_view listener_name, + std::function) = 0; + virtual void UnregisterConnectionListener( + absl::string_view listener_name) = 0; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_H_ diff --git a/sharing/internal/public/connectivity_manager_impl.cc b/sharing/internal/public/connectivity_manager_impl.cc new file mode 100644 index 00000000..8628afe5 --- /dev/null +++ b/sharing/internal/public/connectivity_manager_impl.cc @@ -0,0 +1,95 @@ +// Copyright 2022 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 "sharing/internal/public/connectivity_manager_impl.h" + +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/api/network_monitor.h" +#include "sharing/internal/api/sharing_platform.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/logging.h" + +namespace nearby { +namespace { + +using ::nearby::sharing::api::SharingPlatform; +using ConnectionType = ConnectivityManager::ConnectionType; + +std::string GetConnectionTypeString(ConnectionType connection_type) { + switch (connection_type) { + case ConnectionType::k2G: + return "2G"; + case ConnectionType::k3G: + return "3G"; + case ConnectionType::k4G: + return "4G"; + case ConnectionType::k5G: + return "5G"; + case ConnectionType::kBluetooth: + return "Bluetooth"; + case ConnectionType::kEthernet: + return "Ethernet"; + case ConnectionType::kWifi: + return "WiFi"; + default: + return "Unknown"; + } +} + +} // namespace + +ConnectivityManagerImpl::ConnectivityManagerImpl(SharingPlatform& platform) { + network_monitor_ = platform.CreateNetworkMonitor( + [this](api::NetworkMonitor::ConnectionType connection_type, + bool is_lan_connected) { + ConnectionType new_connection_type = + static_cast(connection_type); + NL_VLOG(1) << ": New connection type:" + << GetConnectionTypeString(new_connection_type); + for (auto& listener : listeners_) { + listener.second(new_connection_type, is_lan_connected); + } + }); +} + +bool ConnectivityManagerImpl::IsLanConnected() { + return network_monitor_->IsLanConnected(); +} + +ConnectionType ConnectivityManagerImpl::GetConnectionType() { + return static_cast(network_monitor_->GetCurrentConnection()); +} + +void ConnectivityManagerImpl::RegisterConnectionListener( + absl::string_view listener_name, + std::function callback) { + listeners_.emplace(listener_name, std::move(callback)); +} + +void ConnectivityManagerImpl::UnregisterConnectionListener( + absl::string_view listener_name) { + listeners_.erase(listener_name); +} + +int ConnectivityManagerImpl::GetListenerCount() const { + return listeners_.size(); +} + +} // namespace nearby diff --git a/sharing/internal/public/connectivity_manager_impl.h b/sharing/internal/public/connectivity_manager_impl.h new file mode 100644 index 00000000..07b70ec6 --- /dev/null +++ b/sharing/internal/public/connectivity_manager_impl.h @@ -0,0 +1,55 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_IMPL_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_IMPL_H_ + +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/api/network_monitor.h" +#include "sharing/internal/api/sharing_platform.h" +#include "sharing/internal/public/connectivity_manager.h" + +namespace nearby { + +// Limitation: this is not thread safe and needs to be enhanced +class ConnectivityManagerImpl : public ConnectivityManager { + public: + explicit ConnectivityManagerImpl( + nearby::sharing::api::SharingPlatform& platform); + + bool IsLanConnected() override; + + ConnectionType GetConnectionType() override; + + void RegisterConnectionListener( + absl::string_view listener_name, + std::function callback) override; + void UnregisterConnectionListener(absl::string_view listener_name) override; + + int GetListenerCount() const; + + private: + absl::flat_hash_map> + listeners_; + std::unique_ptr network_monitor_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONNECTIVITY_MANAGER_IMPL_H_ diff --git a/sharing/internal/public/connectivity_manager_impl_test.cc b/sharing/internal/public/connectivity_manager_impl_test.cc new file mode 100644 index 00000000..3d9f60a3 --- /dev/null +++ b/sharing/internal/public/connectivity_manager_impl_test.cc @@ -0,0 +1,108 @@ +// Copyright 2022 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 "sharing/internal/public/connectivity_manager_impl.h" + +#include +#include +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "sharing/internal/api/mock_network_monitor.h" +#include "sharing/internal/api/mock_sharing_platform.h" +#include "sharing/internal/public/connectivity_manager.h" + +namespace nearby { +namespace { +using ::nearby::sharing::api::MockNetworkMonitor; +using ::nearby::sharing::api::MockSharingPlatform; +using ::testing::_; +using ::testing::ByMove; +using ::testing::Return; + +TEST(ConnectivityManagerImpl, IsLanConnected) { + MockSharingPlatform sharing_platform; + auto network_monitor = std::make_unique(); + MockNetworkMonitor* mock_network_monitor = network_monitor.get(); + EXPECT_CALL(*mock_network_monitor, IsLanConnected()).WillOnce(Return(true)); + EXPECT_CALL(sharing_platform, CreateNetworkMonitor(_)) + .WillOnce(Return(ByMove(std::move(network_monitor)))); + + ConnectivityManagerImpl connectivity_manager_impl(sharing_platform); + EXPECT_TRUE(connectivity_manager_impl.IsLanConnected()); +} + +TEST(ConnectivityManagerImpl, GetConnectionType) { + MockSharingPlatform sharing_platform; + auto network_monitor = std::make_unique(); + MockNetworkMonitor* mock_network_monitor = network_monitor.get(); + EXPECT_CALL(sharing_platform, CreateNetworkMonitor(_)) + .WillOnce(Return(ByMove(std::move(network_monitor)))); + EXPECT_CALL(*mock_network_monitor, GetCurrentConnection()) + .WillOnce(Return(MockNetworkMonitor::ConnectionType::kWifi)); + + ConnectivityManagerImpl connectivity_manager_impl(sharing_platform); + EXPECT_EQ(connectivity_manager_impl.GetConnectionType(), + ConnectivityManager::ConnectionType::kWifi); +} + +TEST(ConnectivityManagerImpl, RegisterConnectionListener) { + std::function listener_1 = + [](ConnectivityManager::ConnectionType connection_type, + bool is_lan_connected) {}; + std::function listener_2 = + [](ConnectivityManager::ConnectionType connection_type, + bool is_lan_connected) {}; + + MockSharingPlatform sharing_platform; + ConnectivityManagerImpl connectivity_manager_impl(sharing_platform); + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 0); + + connectivity_manager_impl.RegisterConnectionListener("listener_1", + listener_1); + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 1); + + connectivity_manager_impl.RegisterConnectionListener("listener_2", + listener_2); + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 2); +} + +TEST(ConnectivityManagerImpl, UnregisterConnectionListener) { + std::function listener_1 = + [](ConnectivityManager::ConnectionType connection_type, + bool is_lan_connected) {}; + std::function listener_2 = + [](ConnectivityManager::ConnectionType connection_type, + bool is_lan_connected) {}; + + MockSharingPlatform sharing_platform; + ConnectivityManagerImpl connectivity_manager_impl(sharing_platform); + connectivity_manager_impl.RegisterConnectionListener("listener_1", + listener_1); + connectivity_manager_impl.RegisterConnectionListener("listener_2", + listener_2); + + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 2); + + connectivity_manager_impl.UnregisterConnectionListener("listener_1"); + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 1); + + connectivity_manager_impl.UnregisterConnectionListener("listener_2"); + EXPECT_EQ(connectivity_manager_impl.GetListenerCount(), 0); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/public/context.h b/sharing/internal/public/context.h new file mode 100644 index 00000000..facc1fd7 --- /dev/null +++ b/sharing/internal/public/context.h @@ -0,0 +1,77 @@ +// Copyright 2021-2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_H_ + +#include + +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/network/url.h" +#include "internal/platform/clock.h" +#include "internal/platform/task_runner.h" +#include "internal/platform/timer.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/public/connectivity_manager.h" + +namespace nearby { + +// Context defines platform implementation-related interfaces. Nearby Sharing +// components should access these interfaces under their environment. +// On different platforms, the implementation of these interfaces are different. +// In order to support test cases on Google3, Nearby Sharing SDK also provides +// a mock implementation of these interfaces. +class Context { + public: + virtual ~Context() = default; + + virtual Clock* GetClock() const = 0; + virtual std::unique_ptr CreateTimer() = 0; + + // Opens a URL by calling the platform API. The platform API should run + // in async mode. However, the callback might be called before + // this function returns, for example if the URL has an error. + // |url| is the URL to open. |callback| is called when the platform API + // completes. absl::StatusCode::kOk is returned when the URL opens + // successfully. + virtual void OpenUrl(const nearby::network::Url& url, + std::function callback) = 0; + virtual ConnectivityManager* GetConnectivityManager() const = 0; + virtual sharing::api::BluetoothAdapter& GetBluetoothAdapter() const = 0; + virtual sharing::api::WifiAdapter& GetWifiAdapter() const = 0; + virtual api::FastInitiationManager& GetFastInitiationManager() const = 0; + virtual std::unique_ptr CreateSequencedTaskRunner() const = 0; + virtual void CopyText(absl::string_view text, + std::function callback) = 0; + + // Creates task runner concurrently. |concurrent_count| is the maximum + // count of tasks running at the same time. + virtual std::unique_ptr CreateConcurrentTaskRunner( + uint32_t concurrent_count) const = 0; + virtual api::Shell& GetShell() const = 0; + + // Provides the API to retrieve TaskRunner to run a task globally. + virtual TaskRunner* GetTaskRunner() = 0; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_H_ diff --git a/sharing/internal/public/context_impl.cc b/sharing/internal/public/context_impl.cc new file mode 100644 index 00000000..c256a14f --- /dev/null +++ b/sharing/internal/public/context_impl.cc @@ -0,0 +1,102 @@ +// Copyright 2021-2023 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 "sharing/internal/public/context_impl.h" + +#include + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/network/url.h" +#include "internal/platform/clock.h" +#include "internal/platform/clock_impl.h" +#include "internal/platform/task_runner.h" +#include "internal/platform/task_runner_impl.h" +#include "internal/platform/timer.h" +#include "internal/platform/timer_impl.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/sharing_platform.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/connectivity_manager_impl.h" + +namespace nearby { + +using ::nearby::sharing::api::SharingPlatform; + +ContextImpl::ContextImpl(SharingPlatform& platform) + : platform_(platform), + clock_(std::make_unique()), + connectivity_manager_( + std::make_unique(platform_)) {} + +Clock* ContextImpl::GetClock() const { return clock_.get(); } + +std::unique_ptr ContextImpl::CreateTimer() { + return std::make_unique(); +} + +void ContextImpl::OpenUrl(const nearby::network::Url& url, + std::function callback) { + platform_.LaunchDefaultBrowserFromURL(url.GetUrlPath(), std::move(callback)); +} + +ConnectivityManager* ContextImpl::GetConnectivityManager() const { + return connectivity_manager_.get(); +} + +sharing::api::BluetoothAdapter& ContextImpl::GetBluetoothAdapter() const { + return platform_.GetBluetoothAdapter(); +} + +sharing::api::WifiAdapter& ContextImpl::GetWifiAdapter() const { + return platform_.GetWifiAdapter(); +} + +api::FastInitiationManager& ContextImpl::GetFastInitiationManager() const { + return platform_.GetFastInitiationManager(); +} + +std::unique_ptr ContextImpl::CreateSequencedTaskRunner() const { + std::unique_ptr task_runner = std::make_unique(1); + return task_runner; +} + +std::unique_ptr ContextImpl::CreateConcurrentTaskRunner( + uint32_t concurrent_count) const { + std::unique_ptr task_runner = + std::make_unique(concurrent_count); + return task_runner; +} + +api::Shell& ContextImpl::GetShell() const { + return platform_.GetShell(); +} + +void ContextImpl::CopyText(absl::string_view text, + std::function callback) { + platform_.CopyText(text, callback); +} + +TaskRunner* ContextImpl::GetTaskRunner() { + return &platform_.GetDefaultTaskRunner(); +} + +} // namespace nearby diff --git a/sharing/internal/public/context_impl.h b/sharing/internal/public/context_impl.h new file mode 100644 index 00000000..4b3d612d --- /dev/null +++ b/sharing/internal/public/context_impl.h @@ -0,0 +1,68 @@ +// Copyright 2021-2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_IMPL_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_IMPL_H_ + +#include + +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/network/url.h" +#include "internal/platform/clock.h" +#include "internal/platform/task_runner.h" +#include "internal/platform/timer.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/sharing_platform.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/context.h" + +namespace nearby { + +class ContextImpl : public Context { + public: + explicit ContextImpl(nearby::sharing::api::SharingPlatform& platform); + ~ContextImpl() override = default; + + Clock* GetClock() const override; + std::unique_ptr CreateTimer() override; + void OpenUrl(const nearby::network::Url& url, + std::function callback) override; + ConnectivityManager* GetConnectivityManager() const override; + sharing::api::BluetoothAdapter& GetBluetoothAdapter() const override; + sharing::api::WifiAdapter& GetWifiAdapter() const override; + api::FastInitiationManager& GetFastInitiationManager() const override; + std::unique_ptr CreateSequencedTaskRunner() const override; + std::unique_ptr CreateConcurrentTaskRunner( + uint32_t concurrent_count) const override; + api::Shell& GetShell() const override; + void CopyText(absl::string_view text, + std::function callback) override; + TaskRunner* GetTaskRunner() override; + + private: + nearby::sharing::api::SharingPlatform& platform_; + std::unique_ptr clock_; + std::unique_ptr connectivity_manager_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_CONTEXT_IMPL_H_ diff --git a/sharing/internal/public/logging.h b/sharing/internal/public/logging.h new file mode 100644 index 00000000..35261248 --- /dev/null +++ b/sharing/internal/public/logging.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_LOGGING_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_LOGGING_H_ + +#include "absl/log/check.h" +#include "absl/log/log.h" + +// Public APIs +// The stream statement must come last, or it won't compile. +#define NL_VLOG(level) VLOG(level) +#define NL_LOG(severity) LOG(severity) + +#define NL_DLOG(severity) DLOG(severity) + +#define NL_CHECK(expr) CHECK(expr) +#define NL_CHECK_EQ(a, b) CHECK_EQ((a), (b)) +#define NL_CHECK_NE(a, b) CHECK_NE((a), (b)) +#define NL_CHECK_GE(a, b) CHECK_GE((a), (b)) +#define NL_CHECK_GT(a, b) CHECK_GT((a), (b)) +#define NL_CHECK_LE(a, b) CHECK_LE((a), (b)) +#define NL_CHECK_LT(a, b) CHECK_LT((a), (b)) + +#define NL_DCHECK(expr) DCHECK((expr)) +#define NL_DCHECK_EQ(a, b) DCHECK_EQ((a), (b)) +#define NL_DCHECK_NE(a, b) DCHECK_NE((a), (b)) +#define NL_DCHECK_GE(a, b) DCHECK_GE((a), (b)) +#define NL_DCHECK_GT(a, b) DCHECK_GT((a), (b)) +#define NL_DCHECK_LE(a, b) DCHECK_LE((a), (b)) +#define NL_DCHECK_LT(a, b) DCHECK_LT((a), (b)) + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_PUBLIC_LOGGING_H_ diff --git a/sharing/internal/test/BUILD b/sharing/internal/test/BUILD new file mode 100644 index 00000000..e9a89663 --- /dev/null +++ b/sharing/internal/test/BUILD @@ -0,0 +1,87 @@ +# Copyright 2023 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. + +licenses(["notice"]) + +cc_library( + name = "nearby_test", + testonly = True, + srcs = [ + "fake_context.cc", + "fake_preference_manager.cc", + "fake_public_certificate_db.cc", + ], + hdrs = [ + "fake_bluetooth_adapter.h", + "fake_bluetooth_adapter_observer.h", + "fake_connectivity_manager.h", + "fake_context.h", + "fake_fast_initiation_manager.h", + "fake_network_monitor.h", + "fake_preference_manager.h", + "fake_public_certificate_db.h", + "fake_shell.h", + "fake_wifi_adapter.h", + "fake_wifi_adapter_observer.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//internal/base", + "//internal/base:bluetooth_address", + "//internal/network:types", + "//internal/platform:types", + "//internal/test", + "//sharing/internal/api:platform", + "//sharing/internal/public:logging", + "//sharing/internal/public:types", + "//sharing/proto:share_cc_proto", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "nearby_test_test", + size = "small", + timeout = "short", + srcs = [ + "fake_bluetooth_adapter_test.cc", + "fake_connectivity_manager_test.cc", + "fake_context_test.cc", + "fake_fast_initiation_manager_test.cc", + "fake_shell_test.cc", + "fake_wifi_adapter_test.cc", + ], + shard_count = 8, + deps = [ + ":nearby_test", + "//internal/network:types", + "//internal/platform:types", + "//internal/platform/implementation/g3", # fixdeps: keep + "//sharing/internal/api:platform", # fixdeps: keep + "//sharing/internal/public:types", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sharing/internal/test/fake_bluetooth_adapter.h b/sharing/internal/test/fake_bluetooth_adapter.h new file mode 100644 index 00000000..da7698db --- /dev/null +++ b/sharing/internal/test/fake_bluetooth_adapter.h @@ -0,0 +1,192 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_H_ + +#include + +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "internal/base/bluetooth_address.h" +#include "internal/base/observer_list.h" +#include "sharing/internal/api/bluetooth_adapter.h" + +namespace nearby { + +class FakeBluetoothAdapter : public sharing::api::BluetoothAdapter { + public: + FakeBluetoothAdapter() { + num_present_received_ = 0; + num_powered_received_ = 0; + } + + ~FakeBluetoothAdapter() override = default; + + bool IsPresent() const override { return is_present_; } + + bool IsPowered() const override { + // If the bluetooth adapter is not present, return false for power status. + if (!is_present_) { + return false; + } + + return is_powered_; + } + + bool IsLowEnergySupported() const override { + return is_low_energy_supported_; + } + + bool IsScanOffloadSupported() const override { + return is_scan_offload_supported_; + } + + bool IsAdvertisementOffloadSupported() const override { + return is_advertisement_offload_supported_; + } + + bool IsExtendedAdvertisingSupported() const override { + return is_extended_advertising_supported_; + } + + bool IsPeripheralRoleSupported() const override { + return is_peripheral_role_supported_; + } + + sharing::api::BluetoothAdapter::PermissionStatus GetOsPermissionStatus() + const override { + return sharing::api::BluetoothAdapter::PermissionStatus::kAllowed; + } + + void SetPowered(bool powered, std::function success_callback, + std::function error_callback) override { + success_callback(); + } + + std::optional GetAdapterId() const override { return "nearby"; } + + std::optional> GetAddress() const override { + std::array output; + if (device::ParseBluetoothAddress( + mac_address_.value(), + absl::MakeSpan(output.data(), output.size()))) { + return output; + } + return {}; + } + + void SetAddress(std::optional bluetooth_address) { + mac_address_ = std::nullopt; + if (bluetooth_address.has_value()) { + mac_address_ = std::make_optional(std::string(bluetooth_address.value())); + } + } + + void AddObserver(Observer* observer) override { + observer_list_.AddObserver(observer); + } + void RemoveObserver(Observer* observer) override { + observer_list_.RemoveObserver(observer); + } + bool HasObserver(Observer* observer) override { + return observer_list_.HasObserver(observer); + } + + // Mock OS bluetooth adapter presence state changed events + void ReceivedAdapterPresentChangedFromOs(bool present) { + num_present_received_ += 1; + + bool was_present = IsPresent(); + bool is_present = present; + + // Only trigger when state of presence changes values + if (was_present != is_present) { + is_present_ = is_present; + for (Observer* observer : observer_list_.GetObservers()) { + if (observer != nullptr) { + observer->AdapterPresentChanged(this, is_present_); + } + } + } + } + + // Mock OS bluetooth adapter powered state changed events + void ReceivedAdapterPoweredChangedFromOs(bool powered) { + num_powered_received_ += 1; + + bool was_powered = IsPowered(); + bool is_powered = powered; + + // Only trigger when state of power changes values + if (was_powered != is_powered) { + is_powered_ = is_powered; + for (Observer* observer : observer_list_.GetObservers()) { + if (observer != nullptr) { + observer->AdapterPoweredChanged(this, is_powered_); + } + } + } + } + + // Mock the behavior where the device does not support BLE + void SetLowEnergySupported(bool is_supported) { + is_low_energy_supported_ = is_supported; + } + + // Mock the behavior where the device/OS not supports BLE scan offload + void SetScanOffloadSupported(bool is_supported) { + is_scan_offload_supported_ = is_supported; + } + + // Mock the behavior where the device does not support offloaded advertisement + void SetAdvertisementOffloadSupported(bool is_supported) { + is_advertisement_offload_supported_ = is_supported; + } + + // Mock the behavior where the device does not support extended advertising + void SetExtendedAdvertisingSupported(bool is_supported) { + is_extended_advertising_supported_ = is_supported; + } + + // Mock the behavior where the device does not support BLE Peripheral Role + void SetPeripheralRoleSupported(bool is_supported) { + is_peripheral_role_supported_ = is_supported; + } + + int GetNumPresentReceivedFromOS() { return num_present_received_; } + int GetNumPoweredReceivedFromOS() { return num_powered_received_; } + + private: + ObserverList observer_list_; + std::optional mac_address_; + bool is_present_ = true; + bool is_powered_ = true; + bool is_low_energy_supported_ = true; + bool is_scan_offload_supported_ = true; + bool is_advertisement_offload_supported_ = true; + bool is_extended_advertising_supported_ = true; + bool is_peripheral_role_supported_ = true; + int num_present_received_; + int num_powered_received_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_H_ diff --git a/sharing/internal/test/fake_bluetooth_adapter_observer.h b/sharing/internal/test/fake_bluetooth_adapter_observer.h new file mode 100644 index 00000000..2412801e --- /dev/null +++ b/sharing/internal/test/fake_bluetooth_adapter_observer.h @@ -0,0 +1,63 @@ +// Copyright 2022 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. + +#ifndef LOCATION_NEARBY_CPP_SHARING_IMPLEMENTATION_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_OBSERVER_H_ +#define LOCATION_NEARBY_CPP_SHARING_IMPLEMENTATION_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_OBSERVER_H_ + +#include "sharing/internal/api/bluetooth_adapter.h" + +namespace nearby { + +class FakeBluetoothAdapterObserver + : public sharing::api::BluetoothAdapter::Observer { + public: + explicit FakeBluetoothAdapterObserver( + sharing::api::BluetoothAdapter* adapter) { + adapter_ = adapter; + num_adapter_present_changed_ = 0; + num_adapter_powered_changed_ = 0; + } + + void AdapterPresentChanged(sharing::api::BluetoothAdapter* adapter, + bool present) override { + if (adapter == adapter_) { + observed_present_value_ = present; + num_adapter_present_changed_ += 1; + } + } + + void AdapterPoweredChanged(sharing::api::BluetoothAdapter* adapter, + bool powered) override { + if (adapter == adapter_) { + observed_powered_value_ = powered; + num_adapter_powered_changed_ += 1; + } + } + bool GetObservedPresentValue() { return observed_present_value_; } + bool GetObservedPoweredValue() { return observed_powered_value_; } + + int GetNumAdapterPresentChanged() { return num_adapter_present_changed_; } + int GetNumAdapterPoweredChanged() { return num_adapter_powered_changed_; } + + private: + sharing::api::BluetoothAdapter* adapter_; + bool observed_present_value_ = true; + bool observed_powered_value_ = true; + int num_adapter_present_changed_; + int num_adapter_powered_changed_; +}; + +} // namespace nearby + +#endif // LOCATION_NEARBY_CPP_SHARING_IMPLEMENTATION_INTERNAL_TEST_FAKE_BLUETOOTH_ADAPTER_OBSERVER_H_ diff --git a/sharing/internal/test/fake_bluetooth_adapter_test.cc b/sharing/internal/test/fake_bluetooth_adapter_test.cc new file mode 100644 index 00000000..268b2a1f --- /dev/null +++ b/sharing/internal/test/fake_bluetooth_adapter_test.cc @@ -0,0 +1,241 @@ +// Copyright 2022 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 "sharing/internal/test/fake_bluetooth_adapter.h" + +#include + +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/test/fake_bluetooth_adapter_observer.h" + +namespace nearby { +namespace { + +TEST(FakeBluetoothAdapter, IsPresent) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsPresent()); +} + +TEST(FakeBluetoothAdapter, IsPowered) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsPowered()); +} + +TEST(FakeBluetoothAdapter, IsLowEnergySupported) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsLowEnergySupported()); +} + +TEST(FakeBluetoothAdapter, IsScanOffloadSupported) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsScanOffloadSupported()); +} + +TEST(FakeBluetoothAdapter, IsAdvertisementOffloadSupported) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsAdvertisementOffloadSupported()); +} + +TEST(FakeBluetoothAdapter, IsExtendedAdvertisingSupported) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsExtendedAdvertisingSupported()); +} + +TEST(FakeBluetoothAdapter, IsPeripheralRoleSupported) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_TRUE(fake_bluetooth_adapter.IsPeripheralRoleSupported()); +} + +TEST(FakeBluetoothAdapter, GetOSPermissionStatus) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_EQ(fake_bluetooth_adapter.GetOsPermissionStatus(), + sharing::api::BluetoothAdapter::PermissionStatus::kAllowed); +} + +TEST(FakeBluetoothAdapter, SetPowered) { + bool powered_on; + std::function success_callback = [&powered_on]() { + powered_on = true; + }; + std::function error_callback = [&powered_on]() { + powered_on = false; + }; + FakeBluetoothAdapter fake_bluetooth_adapter; + fake_bluetooth_adapter.SetPowered(true, success_callback, error_callback); + EXPECT_TRUE(powered_on); +} + +TEST(FakeBluetoothAdapter, GetAdapterId) { + FakeBluetoothAdapter fake_bluetooth_adapter; + EXPECT_EQ(fake_bluetooth_adapter.GetAdapterId(), "nearby"); +} + +TEST(FakeBluetoothAdapter, GetAddress) { + FakeBluetoothAdapter fake_bluetooth_adapter; + fake_bluetooth_adapter.SetAddress("1a:1b:1c:1d:1e:1f"); + // Expected conversion from "1a:1b:1c:1d:1e:1f" + std::array expected_output{{26, 27, 28, 29, 30, 31}}; + EXPECT_EQ(fake_bluetooth_adapter.GetAddress(), expected_output); +} + +TEST(FakeBluetoothAdapter, AddObserver) { + FakeBluetoothAdapter fake_bluetooth_adapter; + FakeBluetoothAdapterObserver fake_observer(&fake_bluetooth_adapter); + fake_bluetooth_adapter.AddObserver(&fake_observer); + EXPECT_TRUE(fake_bluetooth_adapter.HasObserver(&fake_observer)); +} + +TEST(FakeBluetoothAdapter, RemoveObserver) { + FakeBluetoothAdapter fake_bluetooth_adapter; + + FakeBluetoothAdapterObserver fake_observer_1(&fake_bluetooth_adapter); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter); + + fake_bluetooth_adapter.AddObserver(&fake_observer_1); + fake_bluetooth_adapter.AddObserver(&fake_observer_2); + + EXPECT_TRUE(fake_bluetooth_adapter.HasObserver(&fake_observer_1)); + EXPECT_TRUE(fake_bluetooth_adapter.HasObserver(&fake_observer_2)); + + fake_bluetooth_adapter.RemoveObserver(&fake_observer_1); + + EXPECT_FALSE(fake_bluetooth_adapter.HasObserver(&fake_observer_1)); + EXPECT_TRUE(fake_bluetooth_adapter.HasObserver(&fake_observer_2)); +} + +TEST(FakeBluetoothAdapter, HasObserver) { + FakeBluetoothAdapter fake_bluetooth_adapter_1; + FakeBluetoothAdapter fake_bluetooth_adapter_2; + + FakeBluetoothAdapterObserver fake_observer_1(&fake_bluetooth_adapter_1); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter_2); + + fake_bluetooth_adapter_1.AddObserver(&fake_observer_1); + fake_bluetooth_adapter_2.AddObserver(&fake_observer_2); + + EXPECT_TRUE(fake_bluetooth_adapter_1.HasObserver(&fake_observer_1)); + EXPECT_FALSE(fake_bluetooth_adapter_1.HasObserver(&fake_observer_2)); + + EXPECT_TRUE(fake_bluetooth_adapter_2.HasObserver(&fake_observer_2)); + EXPECT_FALSE(fake_bluetooth_adapter_2.HasObserver(&fake_observer_1)); +} + +TEST(FakeBluetoothAdapter, AdapterPresentChanged) { + FakeBluetoothAdapter fake_bluetooth_adapter_1; + FakeBluetoothAdapter fake_bluetooth_adapter_2; + + FakeBluetoothAdapterObserver fake_observer_1a(&fake_bluetooth_adapter_1); + FakeBluetoothAdapterObserver fake_observer_1b(&fake_bluetooth_adapter_1); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter_2); + + fake_bluetooth_adapter_1.AddObserver(&fake_observer_1a); + fake_bluetooth_adapter_1.AddObserver(&fake_observer_1b); + fake_bluetooth_adapter_2.AddObserver(&fake_observer_2); + + // Mocking OS adapter presence changed events (enabled -> disabled/unplugged) + fake_bluetooth_adapter_1.ReceivedAdapterPresentChangedFromOs(false); + + EXPECT_FALSE(fake_observer_1a.GetObservedPresentValue()); + EXPECT_FALSE(fake_observer_1b.GetObservedPresentValue()); + EXPECT_TRUE(fake_observer_2.GetObservedPresentValue()); +} + +TEST(FakeBluetoothAdapter, AdapterPoweredChanged) { + FakeBluetoothAdapter fake_bluetooth_adapter_1; + FakeBluetoothAdapter fake_bluetooth_adapter_2; + + FakeBluetoothAdapterObserver fake_observer_1a(&fake_bluetooth_adapter_1); + FakeBluetoothAdapterObserver fake_observer_1b(&fake_bluetooth_adapter_1); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter_2); + + fake_bluetooth_adapter_1.AddObserver(&fake_observer_1a); + fake_bluetooth_adapter_1.AddObserver(&fake_observer_1b); + fake_bluetooth_adapter_2.AddObserver(&fake_observer_2); + + // Mocking OS adapter powered changed events (on -> off) + fake_bluetooth_adapter_1.ReceivedAdapterPoweredChangedFromOs(false); + + EXPECT_FALSE(fake_observer_1a.GetObservedPoweredValue()); + EXPECT_FALSE(fake_observer_1b.GetObservedPoweredValue()); + EXPECT_TRUE(fake_observer_2.GetObservedPoweredValue()); +} + +TEST(FakeBluetoothAdapter, RepeatedAdapterPresentChanged) { + FakeBluetoothAdapter fake_bluetooth_adapter; + + FakeBluetoothAdapterObserver fake_observer_1(&fake_bluetooth_adapter); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter); + + fake_bluetooth_adapter.AddObserver(&fake_observer_1); + fake_bluetooth_adapter.AddObserver(&fake_observer_2); + + // Mocking first OS adapter present changed event (enabled -> + // disabled/unplugged) + fake_bluetooth_adapter.ReceivedAdapterPresentChangedFromOs(false); + + EXPECT_EQ(fake_bluetooth_adapter.GetNumPresentReceivedFromOS(), 1); + EXPECT_EQ(fake_observer_1.GetNumAdapterPresentChanged(), 1); + EXPECT_EQ(fake_observer_2.GetNumAdapterPresentChanged(), 1); + + // Mocking second OS adapter present changed event (enabled -> + // disabled/unplugged) + fake_bluetooth_adapter.ReceivedAdapterPresentChangedFromOs(false); + + // Since it is a repeated event, do not inform observers + // i.e. observers have still only updated the state change once + EXPECT_EQ(fake_bluetooth_adapter.GetNumPresentReceivedFromOS(), 2); + EXPECT_EQ(fake_observer_1.GetNumAdapterPresentChanged(), 1); + EXPECT_EQ(fake_observer_2.GetNumAdapterPresentChanged(), 1); + + EXPECT_FALSE(fake_observer_1.GetObservedPresentValue()); + EXPECT_FALSE(fake_observer_2.GetObservedPresentValue()); +} + +TEST(FakeBluetoothAdapter, RepeatedAdapterPoweredChanged) { + FakeBluetoothAdapter fake_bluetooth_adapter; + + FakeBluetoothAdapterObserver fake_observer_1(&fake_bluetooth_adapter); + FakeBluetoothAdapterObserver fake_observer_2(&fake_bluetooth_adapter); + + fake_bluetooth_adapter.AddObserver(&fake_observer_1); + fake_bluetooth_adapter.AddObserver(&fake_observer_2); + + // Mocking first OS adapter powered changed event (on -> off) + fake_bluetooth_adapter.ReceivedAdapterPoweredChangedFromOs(false); + + EXPECT_EQ(fake_bluetooth_adapter.GetNumPoweredReceivedFromOS(), 1); + EXPECT_EQ(fake_observer_1.GetNumAdapterPoweredChanged(), 1); + EXPECT_EQ(fake_observer_2.GetNumAdapterPoweredChanged(), 1); + + // Mocking second OS adapter powered changed event (on -> off) + fake_bluetooth_adapter.ReceivedAdapterPoweredChangedFromOs(false); + + // Since it is a repeated event, do not inform observers + // i.e. observers have still only updated the state change once + EXPECT_EQ(fake_bluetooth_adapter.GetNumPoweredReceivedFromOS(), 2); + EXPECT_EQ(fake_observer_1.GetNumAdapterPoweredChanged(), 1); + EXPECT_EQ(fake_observer_2.GetNumAdapterPoweredChanged(), 1); + + EXPECT_FALSE(fake_observer_1.GetObservedPoweredValue()); + EXPECT_FALSE(fake_observer_2.GetObservedPoweredValue()); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/test/fake_connectivity_manager.h b/sharing/internal/test/fake_connectivity_manager.h new file mode 100644 index 00000000..2cbe2a94 --- /dev/null +++ b/sharing/internal/test/fake_connectivity_manager.h @@ -0,0 +1,64 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONNECTIVITY_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONNECTIVITY_MANAGER_H_ + +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/public/connectivity_manager.h" + +namespace nearby { + +class FakeConnectivityManager : public ConnectivityManager { + public: + bool IsLanConnected() override { return is_lan_connected_; } + + ConnectionType GetConnectionType() override { return connection_type_; } + + void RegisterConnectionListener( + absl::string_view listener_name, + std::function callback) override { + listeners_.emplace(listener_name, std::move(callback)); + } + void UnregisterConnectionListener(absl::string_view listener_name) override { + listeners_.erase(listener_name); + } + + // Mocks connectivity methods. + void SetLanConnected(bool connected) { is_lan_connected_ = connected; } + + // Mocks connectivity methods. + void SetConnectionType(ConnectionType connection_type) { + connection_type_ = connection_type; + for (auto& listener : listeners_) { + listener.second(connection_type, is_lan_connected_); + } + } + int GetListenerCount() const { return listeners_.size(); } + + private: + bool is_lan_connected_ = true; + ConnectionType connection_type_ = ConnectionType::kWifi; + absl::flat_hash_map> + listeners_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONNECTIVITY_MANAGER_H_ diff --git a/sharing/internal/test/fake_connectivity_manager_test.cc b/sharing/internal/test/fake_connectivity_manager_test.cc new file mode 100644 index 00000000..5b883cad --- /dev/null +++ b/sharing/internal/test/fake_connectivity_manager_test.cc @@ -0,0 +1,71 @@ +// Copyright 2021 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 "sharing/internal/test/fake_connectivity_manager.h" + +#include + +#include "gtest/gtest.h" +#include "sharing/internal/public/connectivity_manager.h" + +namespace nearby { +namespace { + +TEST(FakeConnectivityManager, TestIsLanConnected) { + FakeConnectivityManager connection_manager; + bool is_lan_connected = connection_manager.IsLanConnected(); + ASSERT_TRUE(is_lan_connected); + connection_manager.SetLanConnected(false); + EXPECT_FALSE(connection_manager.IsLanConnected()); +} + +TEST(FakeConnectivityManager, TestGetCurrentConnection) { + FakeConnectivityManager connection_manager; + ConnectivityManager::ConnectionType connection = + connection_manager.GetConnectionType(); + EXPECT_EQ(connection, ConnectivityManager::ConnectionType::kWifi); + connection_manager.SetConnectionType( + ConnectivityManager::ConnectionType::kEthernet); + EXPECT_EQ(connection_manager.GetConnectionType(), + ConnectivityManager::ConnectionType::kEthernet); +} + +TEST(FakeConnectivityManager, TestListener) { + FakeConnectivityManager connection_manager; + ConnectivityManager::ConnectionType connection_type = + connection_manager.GetConnectionType(); + bool is_lan_connected = false; + connection_manager.RegisterConnectionListener( + "test", + [&connection_type, &is_lan_connected]( + ConnectivityManager::ConnectionType connection, bool connected) { + connection_type = connection; + is_lan_connected = connected; + }); + EXPECT_EQ(connection_manager.GetListenerCount(), 1); + connection_manager.SetConnectionType( + ConnectivityManager::ConnectionType::kEthernet); + connection_manager.SetLanConnected(true); + EXPECT_EQ(connection_type, ConnectivityManager::ConnectionType::kEthernet); + ASSERT_TRUE(is_lan_connected); + connection_manager.UnregisterConnectionListener("test"); + EXPECT_EQ(connection_manager.GetListenerCount(), 0); + connection_manager.SetConnectionType( + ConnectivityManager::ConnectionType::kWifi); + EXPECT_EQ(connection_type, ConnectivityManager::ConnectionType::kEthernet); + EXPECT_TRUE(is_lan_connected); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/test/fake_context.cc b/sharing/internal/test/fake_context.cc new file mode 100644 index 00000000..53887f2a --- /dev/null +++ b/sharing/internal/test/fake_context.cc @@ -0,0 +1,108 @@ +// Copyright 2021-2023 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 "sharing/internal/test/fake_context.h" + +#include + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/network/url.h" +#include "internal/platform/clock.h" +#include "internal/platform/task_runner.h" +#include "internal/platform/timer.h" +#include "internal/test/fake_clock.h" +#include "internal/test/fake_task_runner.h" +#include "internal/test/fake_timer.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/test/fake_bluetooth_adapter.h" +#include "sharing/internal/test/fake_connectivity_manager.h" +#include "sharing/internal/test/fake_fast_initiation_manager.h" +#include "sharing/internal/test/fake_shell.h" +#include "sharing/internal/test/fake_wifi_adapter.h" + +namespace nearby { + +FakeContext::FakeContext() + : fake_clock_(std::make_unique()), + connectivity_manager_(std::make_unique()), + bluetooth_adapter_(std::make_unique()), + wifi_adapter_(std::make_unique()), + fast_initiation_manager_(std::make_unique()), + shell_(std::make_unique()), + executor_(std::make_unique( + dynamic_cast(GetClock()), 5)) {} + +Clock* FakeContext::GetClock() const { return fake_clock_.get(); } + +std::unique_ptr FakeContext::CreateTimer() { + return std::make_unique(fake_clock_.get()); +} + +void FakeContext::OpenUrl(const nearby::network::Url& url, + std::function callback) { + // OpenUrl is an interface that depends on platform API. In a mock method, it + // returns OK to avoid breaking test cases in the Nearby Sharing SDK. + std::move(callback)(absl::OkStatus()); +} + +void FakeContext::CopyText(const absl::string_view text, + std::function callback) { + // CopyText is an interface that depends on platform API. In a mock method, it + // returns OK to avoid breaking test cases in the Nearby Sharing SDK. + std::move(callback)(absl::OkStatus()); +} + +ConnectivityManager* FakeContext::GetConnectivityManager() const { + return connectivity_manager_.get(); +} + +sharing::api::BluetoothAdapter& FakeContext::GetBluetoothAdapter() const { + return *bluetooth_adapter_; +} + +sharing::api::WifiAdapter& FakeContext::GetWifiAdapter() const { + return *wifi_adapter_; +} + +api::FastInitiationManager& FakeContext::GetFastInitiationManager() const { + return *fast_initiation_manager_; +} + +std::unique_ptr FakeContext::CreateSequencedTaskRunner() const { + std::unique_ptr task_runner = + std::make_unique(dynamic_cast(GetClock()), 1); + return task_runner; +} + +std::unique_ptr FakeContext::CreateConcurrentTaskRunner( + uint32_t concurrent_count) const { + std::unique_ptr task_runner = std::make_unique( + dynamic_cast(GetClock()), concurrent_count); + return task_runner; +} + +api::Shell& FakeContext::GetShell() const { return *shell_; } + +TaskRunner* FakeContext::GetTaskRunner() { return executor_.get(); } + +} // namespace nearby diff --git a/sharing/internal/test/fake_context.h b/sharing/internal/test/fake_context.h new file mode 100644 index 00000000..305f46cd --- /dev/null +++ b/sharing/internal/test/fake_context.h @@ -0,0 +1,74 @@ +// Copyright 2021-2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONTEXT_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONTEXT_H_ + +#include + +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/network/url.h" +#include "internal/platform/clock.h" +#include "internal/platform/task_runner.h" +#include "internal/platform/timer.h" +#include "internal/test/fake_clock.h" +#include "sharing/internal/api/bluetooth_adapter.h" +#include "sharing/internal/api/fast_initiation_manager.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/context.h" + +namespace nearby { + +class FakeContext : public Context { + public: + FakeContext(); + ~FakeContext() override = default; + + Clock* GetClock() const override; + std::unique_ptr CreateTimer() override; + void OpenUrl(const nearby::network::Url& url, + std::function callback) override; + ConnectivityManager* GetConnectivityManager() const override; + sharing::api::BluetoothAdapter& GetBluetoothAdapter() const override; + sharing::api::WifiAdapter& GetWifiAdapter() const override; + api::FastInitiationManager& GetFastInitiationManager() const override; + std::unique_ptr CreateSequencedTaskRunner() const override; + std::unique_ptr CreateConcurrentTaskRunner( + uint32_t concurrent_count) const override; + api::Shell& GetShell() const override; + void CopyText(absl::string_view text, + std::function callback) override; + TaskRunner* GetTaskRunner() override; + + FakeClock* fake_clock() const { return fake_clock_.get(); } + + private: + std::unique_ptr fake_clock_; + std::unique_ptr connectivity_manager_; + std::unique_ptr bluetooth_adapter_; + std::unique_ptr wifi_adapter_; + std::unique_ptr fast_initiation_manager_; + std::unique_ptr shell_; + std::unique_ptr executor_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_CONTEXT_H_ diff --git a/sharing/internal/test/fake_context_test.cc b/sharing/internal/test/fake_context_test.cc new file mode 100644 index 00000000..0b0c3152 --- /dev/null +++ b/sharing/internal/test/fake_context_test.cc @@ -0,0 +1,48 @@ +// Copyright 2021-2023 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 "sharing/internal/test/fake_context.h" + +#include "gtest/gtest.h" +#include "absl/synchronization/notification.h" +#include "absl/time/time.h" +#include "internal/platform/task_runner.h" + +namespace nearby { +namespace { + +TEST(FakeContext, TestAccessMockContext) { + FakeContext context; + EXPECT_NE(context.GetClock(), nullptr); + EXPECT_NE(context.CreateTimer(), nullptr); + EXPECT_NE(context.GetConnectivityManager(), nullptr); + EXPECT_NE(context.CreateSequencedTaskRunner(), nullptr); + EXPECT_NE(context.CreateConcurrentTaskRunner(5), nullptr); +} + +TEST(FakeContext, ExecuteTask) { + FakeContext context; + absl::Notification notification; + bool is_called = false; + context.GetTaskRunner()->PostTask([&]() { + is_called = true; + notification.Notify(); + }); + + EXPECT_TRUE(notification.WaitForNotificationWithTimeout(absl::Seconds(1))); + EXPECT_TRUE(is_called); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/test/fake_fast_initiation_manager.h b/sharing/internal/test/fake_fast_initiation_manager.h new file mode 100644 index 00000000..9b58d3fc --- /dev/null +++ b/sharing/internal/test/fake_fast_initiation_manager.h @@ -0,0 +1,98 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_FAST_INITIATION_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_FAST_INITIATION_MANAGER_H_ + +#include +#include + +#include "sharing/internal/api/fast_init_ble_beacon.h" +#include "sharing/internal/api/fast_initiation_manager.h" + +namespace nearby { + +class FakeFastInitiationManager : public api::FastInitiationManager { + public: + FakeFastInitiationManager() : api::FastInitiationManager() {} + void StartAdvertising(api::FastInitBleBeacon::FastInitType type, + std::function callback, + std::function + error_callback) override { + advertising_started_callback_ = std::move(callback); + advertising_error_callback_ = std::move(error_callback); + is_advertising_ = true; + } + + void StopAdvertising(std::function callback) override { + advertising_stopped_callback_ = std::move(callback); + is_advertising_ = false; + } + + void StartScanning(std::function devices_discovered_callback, + std::function devices_not_discovered_callback, + std::function + error_callback) override { + scanning_discovered_callback_ = std::move(devices_discovered_callback); + scanning_not_discovered_callback_ = + std::move(devices_not_discovered_callback); + scanning_error_callback_ = std::move(error_callback); + is_scanning_ = true; + } + + void StopScanning(std::function callback) override { + scanning_stopped_callback_ = std::move(callback); + is_scanning_ = false; + } + + bool IsAdvertising() override { return is_advertising_; } + + bool IsScanning() override { return is_scanning_; } + + // Mock methods to simulate OS advertising/scanning event callbacks + void SetAdvertisingStarted() { advertising_started_callback_(); } + + void SetAdvertisingError(api::FastInitiationManager::Error error) { + advertising_error_callback_(error); + } + + void SetAdvertisingStopped() { advertising_stopped_callback_(); } + + void SetScanningDiscovered() { scanning_discovered_callback_(); } + + void SetScanningNotDiscovered() { scanning_not_discovered_callback_(); } + + void SetScanningError(api::FastInitiationManager::Error error) { + scanning_error_callback_(error); + } + + void SetScanningStopped() { scanning_stopped_callback_(); } + + private: + bool is_advertising_ = false; + bool is_scanning_ = false; + std::function advertising_started_callback_; + std::function + advertising_error_callback_; + std::function advertising_stopped_callback_; + std::function scanning_discovered_callback_; + std::function scanning_not_discovered_callback_; + std::function + scanning_error_callback_; + std::function scanning_stopped_callback_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_FAST_INITIATION_MANAGER_H_ diff --git a/sharing/internal/test/fake_fast_initiation_manager_test.cc b/sharing/internal/test/fake_fast_initiation_manager_test.cc new file mode 100644 index 00000000..75cc02d4 --- /dev/null +++ b/sharing/internal/test/fake_fast_initiation_manager_test.cc @@ -0,0 +1,83 @@ +// Copyright 2022 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 "sharing/internal/test/fake_fast_initiation_manager.h" + +#include +#include + +#include "gtest/gtest.h" +#include "sharing/internal/api/fast_init_ble_beacon.h" +#include "sharing/internal/api/fast_initiation_manager.h" + +namespace nearby { +namespace { + +TEST(FakeFastInitiationManager, StartAdvertising) { + bool started = false; + std::function success_callback = [&started]() { started = true; }; + std::function error_callback = + [](api::FastInitiationManager::Error) {}; + + FakeFastInitiationManager fast_initiation_manager; + fast_initiation_manager.StartAdvertising( + api::FastInitBleBeacon::FastInitType::kNotify, success_callback, + error_callback); + fast_initiation_manager.SetAdvertisingStarted(); + + EXPECT_TRUE(started); +} + +TEST(FakeFastInitiationManager, StopAdvertising) { + bool stopped = false; + std::function success_callback = [&stopped]() { stopped = true; }; + + FakeFastInitiationManager fast_initiation_manager; + fast_initiation_manager.StopAdvertising(success_callback); + fast_initiation_manager.SetAdvertisingStopped(); + + EXPECT_TRUE(stopped); +} + +TEST(FakeFastInitiationManager, StartScanning) { + bool devices_discovered = false; + std::function devices_discovered_callback = [&devices_discovered]() { + devices_discovered = true; + }; + std::function devices_not_discovered_callback = []() {}; + std::function error_callback = + [](api::FastInitiationManager::Error) {}; + + FakeFastInitiationManager fast_initiation_manager; + fast_initiation_manager.StartScanning(devices_discovered_callback, + devices_not_discovered_callback, + error_callback); + fast_initiation_manager.SetScanningDiscovered(); + + EXPECT_TRUE(devices_discovered); +} + +TEST(FakeFastInitiationManager, StopScanning) { + bool stopped = false; + std::function success_callback = [&stopped]() { stopped = true; }; + + FakeFastInitiationManager fast_initiation_manager; + fast_initiation_manager.StopScanning(success_callback); + fast_initiation_manager.SetScanningStopped(); + + EXPECT_TRUE(stopped); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/test/fake_network_monitor.h b/sharing/internal/test/fake_network_monitor.h new file mode 100644 index 00000000..46c21eac --- /dev/null +++ b/sharing/internal/test/fake_network_monitor.h @@ -0,0 +1,51 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_NETWORK_MONITOR_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_NETWORK_MONITOR_H_ + +#include + +#include "sharing/internal/api/network_monitor.h" + +namespace nearby { + +class FakeNetworkMonitor : public api::NetworkMonitor { + public: + explicit FakeNetworkMonitor( + std::function callback) + : api::NetworkMonitor(callback) {} + + ~FakeNetworkMonitor() override { callback_ = nullptr; } + + bool IsLanConnected() override { return is_lan_connected_; } + + api::NetworkMonitor::ConnectionType GetCurrentConnection() override { + return api::NetworkMonitor::ConnectionType::kWifi; + } + + void SetLanConnected(bool connected) { is_lan_connected_ = connected; } + + void TestNetworkChangeToEthernet() { + callback_(api::NetworkMonitor::ConnectionType::kEthernet, + is_lan_connected_); + } + + private: + bool is_lan_connected_ = true; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_NETWORK_MONITOR_H_ diff --git a/sharing/internal/test/fake_preference_manager.cc b/sharing/internal/test/fake_preference_manager.cc new file mode 100644 index 00000000..9f3e9966 --- /dev/null +++ b/sharing/internal/test/fake_preference_manager.cc @@ -0,0 +1,325 @@ +// Copyright 2023 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 "sharing/internal/test/fake_preference_manager.h" +#include +#include +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "sharing/internal/api/private_certificate_data.h" + +namespace nearby { +using ::nearby::sharing::api::PrivateCertificateData; + +template +void FakePreferenceManager::SetValue(absl::string_view key, T value) { + if (values_.contains(key)) { + const Data& data = values_.at(key); + if (std::holds_alternative(data)) { + if (std::get(data) == value) { + return; + } + } + values_.erase(key); + } + values_.emplace(key, value); + NotifyPreferenceChanged(key); +} + +template +T FakePreferenceManager::GetValue(absl::string_view key, + const T& default_value) const { + if (values_.contains(key)) { + const Data& data = values_.at(key); + if (std::holds_alternative(data)) { + return std::get(data); + } + } + return default_value; +} + +template +void FakePreferenceManager::SetArray(absl::string_view key, + absl::Span values) { + std::vector data; + data.reserve(values.size()); + for (T value : values) { + data.push_back(value); + } + if (arrays_.contains(key)) { + if (data == arrays_.at(key)) { + return; + } + arrays_.erase(key); + } + arrays_.emplace(key, data); + NotifyPreferenceChanged(key); +} + +template +std::vector FakePreferenceManager::GetArray( + absl::string_view key, absl::Span default_value) const { + if (arrays_.contains(key)) { + const std::vector& data = arrays_.at(key); + std::vector result; + result.reserve(data.size()); + for (const Data& data : data) { + if (std::holds_alternative(data)) { + result.push_back(std::get(data)); + } + } + return result; + } + return std::vector(default_value.begin(), default_value.end()); +} + +template +void FakePreferenceManager::SetDictionaryValue( + absl::string_view key, absl::string_view dictionary_item, T value) { + auto& dictionary = dictionaries_[key]; + if (dictionary.contains(dictionary_item)) { + const Data& data = dictionary.at(dictionary_item); + if (std::holds_alternative(data)) { + if (std::get(data) == value) { + return; + } + } + dictionary.erase(dictionary_item); + } + dictionary.emplace(dictionary_item, value); + NotifyPreferenceChanged(key); +} + +template +std::optional FakePreferenceManager::GetDictionaryValue( + absl::string_view key, absl::string_view dictionary_item) const { + if (!dictionaries_.contains(key)) { + return std::nullopt; + } + const auto& dictionary = dictionaries_.at(key); + if (dictionary.contains(dictionary_item)) { + const Data& data = dictionary.at(dictionary_item); + if (std::holds_alternative(data)) { + return std::get(data); + } + } + return std::nullopt; +} + +void FakePreferenceManager::SetBoolean(absl::string_view key, bool value) { + SetValue(key, value); +} + +void FakePreferenceManager::SetInteger(absl::string_view key, int value) { + SetValue(key, value); +} + +void FakePreferenceManager::SetInt64(absl::string_view key, int64_t value) { + SetValue(key, value); +} + +void FakePreferenceManager::SetString(absl::string_view key, + absl::string_view value) { + SetValue(key, std::string(value)); +} + +void FakePreferenceManager::SetTime(absl::string_view key, absl::Time value) { + SetValue(key, absl::ToUnixNanos(value)); +} + +void FakePreferenceManager::SetBooleanArray(absl::string_view key, + absl::Span value) { + SetArray(key, value); +} + +void FakePreferenceManager::SetIntegerArray(absl::string_view key, + absl::Span value) { + SetArray(key, value); +} + +void FakePreferenceManager::SetInt64Array(absl::string_view key, + absl::Span value) { + SetArray(key, value); +} + +void FakePreferenceManager::SetStringArray( + absl::string_view key, absl::Span value) { + SetArray(key, value); +} + +void FakePreferenceManager::SetPrivateCertificateArray( + absl::string_view key, + absl::Span value) { + if (certs_.contains(key)) { + certs_.erase(key); + } + certs_.emplace( + key, std::vector(value.begin(), value.end())); +} + +void FakePreferenceManager::SetCertificateExpirationArray( + absl::string_view key, + absl::Span> value) { + if (cert_expirations_.contains(key)) { + cert_expirations_.erase(key); + } + cert_expirations_.emplace(key, std::vector>( + value.begin(), value.end())); +} + +void FakePreferenceManager::SetDictionaryBooleanValue( + absl::string_view key, absl::string_view dictionary_item, bool value) { + SetDictionaryValue(key, dictionary_item, value); +} + +void FakePreferenceManager::SetDictionaryIntegerValue( + absl::string_view key, absl::string_view dictionary_item, int value) { + SetDictionaryValue(key, dictionary_item, value); +} + +void FakePreferenceManager::SetDictionaryInt64Value( + absl::string_view key, absl::string_view dictionary_item, int64_t value) { + SetDictionaryValue(key, dictionary_item, value); +} + +void FakePreferenceManager::SetDictionaryStringValue( + absl::string_view key, absl::string_view dictionary_item, + std::string value) { + SetDictionaryValue(key, dictionary_item, value); +} + +void FakePreferenceManager::RemoveDictionaryItem( + absl::string_view key, absl::string_view dictionary_item) { + if (!dictionaries_.contains(key)) { + return; + } + auto& dictionary = dictionaries_[key]; + dictionary.erase(dictionary_item); + NotifyPreferenceChanged(key); +} + + +bool FakePreferenceManager::GetBoolean(absl::string_view key, + bool default_value) const { + return GetValue(key, default_value); +} + +int FakePreferenceManager::GetInteger(absl::string_view key, + int default_value) const { + return GetValue(key, default_value); +} + +int64_t FakePreferenceManager::GetInt64(absl::string_view key, + int64_t default_value) const { + return GetValue(key, default_value); +} + +std::string FakePreferenceManager::GetString( + absl::string_view key, const std::string& default_value) const { + return GetValue(key, default_value); +} + +absl::Time FakePreferenceManager::GetTime(absl::string_view key, + absl::Time default_value) const { + return absl::FromUnixNanos(GetValue(key, absl::ToUnixNanos(default_value))); +} + +std::vector FakePreferenceManager::GetBooleanArray( + absl::string_view key, absl::Span default_value) const { + return GetArray(key, default_value); +} + +std::vector FakePreferenceManager::GetIntegerArray( + absl::string_view key, absl::Span default_value) const { + return GetArray(key, default_value); +} + +std::vector FakePreferenceManager::GetInt64Array( + absl::string_view key, absl::Span default_value) const { + return GetArray(key, default_value); +} + +std::vector FakePreferenceManager::GetStringArray( + absl::string_view key, absl::Span default_value) const { + return GetArray(key, default_value); +} + +std::vector +FakePreferenceManager::GetPrivateCertificateArray(absl::string_view key) const { + if (certs_.contains(key)) { + return certs_.at(key); + } + return std::vector(); +} + +std::vector> +FakePreferenceManager::GetCertificateExpirationArray( + absl::string_view key) const { + if (cert_expirations_.contains(key)) { + return cert_expirations_.at(key); + } + return std::vector>(); +} + +std::optional FakePreferenceManager::GetDictionaryBooleanValue( + absl::string_view key, absl::string_view dictionary_item) const { + return GetDictionaryValue(key, dictionary_item); +} + +std::optional FakePreferenceManager::GetDictionaryIntegerValue( + absl::string_view key, absl::string_view dictionary_item) const { + return GetDictionaryValue(key, dictionary_item); +} + +std::optional FakePreferenceManager::GetDictionaryInt64Value( + absl::string_view key, absl::string_view dictionary_item) const { + return GetDictionaryValue(key, dictionary_item); +} + +std::optional FakePreferenceManager::GetDictionaryStringValue( + absl::string_view key, absl::string_view dictionary_item) const { + return GetDictionaryValue(key, dictionary_item); +} + +void FakePreferenceManager::Remove(absl::string_view key) { + values_.erase(key); + arrays_.erase(key); + dictionaries_.erase(key); + NotifyPreferenceChanged(key); +} + +void FakePreferenceManager::NotifyPreferenceChanged(absl::string_view key) { + for (const auto& observer : observers_) { + observer.second(key); + } +} + +void FakePreferenceManager::AddObserver( + absl::string_view name, + std::function observer) { + observers_.emplace(name, observer); +} + +void FakePreferenceManager::RemoveObserver(absl::string_view name) { + observers_.erase(name); +} + +} // namespace nearby diff --git a/sharing/internal/test/fake_preference_manager.h b/sharing/internal/test/fake_preference_manager.h new file mode 100644 index 00000000..709e4d27 --- /dev/null +++ b/sharing/internal/test/fake_preference_manager.h @@ -0,0 +1,153 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PREFERENCE_MANAGER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PREFERENCE_MANAGER_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/api/private_certificate_data.h" + +namespace nearby { + +// An in memory fake PreferenceManager implementation for testing. +class FakePreferenceManager : public nearby::sharing::api::PreferenceManager { + public: + void SetBoolean(absl::string_view key, bool value) override; + void SetInteger(absl::string_view key, int value) override; + void SetInt64(absl::string_view key, int64_t value) override; + void SetString(absl::string_view key, absl::string_view value) override; + void SetTime(absl::string_view key, absl::Time value) override; + + void SetBooleanArray(absl::string_view key, + absl::Span value) override; + void SetIntegerArray(absl::string_view key, + absl::Span value) override; + void SetInt64Array(absl::string_view key, + absl::Span value) override; + void SetStringArray(absl::string_view key, + absl::Span value) override; + void SetPrivateCertificateArray( + absl::string_view key, + absl::Span value) + override; + void SetCertificateExpirationArray( + absl::string_view key, + absl::Span> value) override; + + void SetDictionaryBooleanValue(absl::string_view key, + absl::string_view dictionary_item, + bool value) override; + void SetDictionaryIntegerValue(absl::string_view key, + absl::string_view dictionary_item, + int value) override; + void SetDictionaryInt64Value(absl::string_view key, + absl::string_view dictionary_item, + int64_t value) override; + void SetDictionaryStringValue(absl::string_view key, + absl::string_view dictionary_item, + std::string value) override; + void RemoveDictionaryItem(absl::string_view key, + absl::string_view dictionary_item) override; + + bool GetBoolean(absl::string_view key, bool default_value) const override; + int GetInteger(absl::string_view key, int default_value) const override; + int64_t GetInt64(absl::string_view key, int64_t default_value) const override; + std::string GetString(absl::string_view key, + const std::string& default_value) const override; + absl::Time GetTime(absl::string_view key, + absl::Time default_value) const override; + + std::vector GetBooleanArray( + absl::string_view key, + absl::Span default_value) const override; + std::vector GetIntegerArray( + absl::string_view key, + absl::Span default_value) const override; + std::vector GetInt64Array( + absl::string_view key, + absl::Span default_value) const override; + std::vector GetStringArray( + absl::string_view key, + absl::Span default_value) const override; + std::vector + GetPrivateCertificateArray(absl::string_view key) const override; + std::vector> GetCertificateExpirationArray( + absl::string_view key) const override; + + std::optional GetDictionaryBooleanValue( + absl::string_view key, absl::string_view dictionary_item) const override; + std::optional GetDictionaryIntegerValue( + absl::string_view key, absl::string_view dictionary_item) const override; + std::optional GetDictionaryInt64Value( + absl::string_view key, absl::string_view dictionary_item) const override; + std::optional GetDictionaryStringValue( + absl::string_view key, absl::string_view dictionary_item) const override; + + void Remove(absl::string_view key) override; + + void AddObserver( + absl::string_view name, + std::function observer) override; + void RemoveObserver(absl::string_view name) override; + + private: + typedef std::variant Data; + + template void SetValue(absl::string_view key, T value); + template + T GetValue(absl::string_view key, const T& default_value) const; + template + void SetArray(absl::string_view key, absl::Span values); + template + std::vector GetArray(absl::string_view key, + absl::Span default_value) const; + template + void SetDictionaryValue(absl::string_view key, + absl::string_view dictionary_item, T value); + template + std::optional GetDictionaryValue(absl::string_view key, + absl::string_view dictionary_item) const; + + void NotifyPreferenceChanged(absl::string_view key); + + absl::flat_hash_map values_; + absl::flat_hash_map> + dictionaries_; + absl::flat_hash_map> arrays_; + absl::flat_hash_map> + certs_; + absl::flat_hash_map>> + cert_expirations_; + + absl::flat_hash_map> + observers_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PREFERENCE_MANAGER_H_ diff --git a/sharing/internal/test/fake_public_certificate_db.cc b/sharing/internal/test/fake_public_certificate_db.cc new file mode 100644 index 00000000..21494484 --- /dev/null +++ b/sharing/internal/test/fake_public_certificate_db.cc @@ -0,0 +1,81 @@ +// Copyright 2022 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 "sharing/internal/test/fake_public_certificate_db.h" + +#include +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/types/span.h" +#include "sharing/internal/api/public_certificate_database.h" +#include "sharing/proto/rpc_resources.pb.h" + +namespace nearby { + +using ::nearby::sharing::proto::PublicCertificate; + +void FakePublicCertificateDb::Initialize( + absl::AnyInvocable + callback) { + std::move(callback)(PublicCertificateDatabase::InitStatus::kOk); +} + +void FakePublicCertificateDb::LoadEntries( + absl::AnyInvocable>) &&> + callback) { + auto result = std::make_unique>(); + auto it = entries_.begin(); + while (it != entries_.end()) { + result->push_back(it->second); + ++it; + } + + std::move(callback)(true, std::move(result)); +} + +void FakePublicCertificateDb::AddCertificates( + absl::Span certificates, + absl::AnyInvocable callback) { + for (const auto& cert : certificates) { + if (entries_.contains(cert.secret_id())) { + entries_.erase(cert.secret_id()); + } + entries_.emplace(cert.secret_id(), cert); + } + std::move(callback)(true); +} + +void FakePublicCertificateDb::RemoveCertificatesById( + std::vector ids_to_remove, + absl::AnyInvocable callback) { + auto it = ids_to_remove.begin(); + while (it != ids_to_remove.end()) { + entries_.erase(*it); + ++it; + } + std::move(callback)(true); +} + +void FakePublicCertificateDb::Destroy( + absl::AnyInvocable callback) { + entries_.clear(); + std::move(callback)(true); +} + +} // namespace nearby diff --git a/sharing/internal/test/fake_public_certificate_db.h b/sharing/internal/test/fake_public_certificate_db.h new file mode 100644 index 00000000..e555d910 --- /dev/null +++ b/sharing/internal/test/fake_public_certificate_db.h @@ -0,0 +1,64 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PUBLIC_CERTIFICATE_DB_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PUBLIC_CERTIFICATE_DB_H_ + +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/functional/any_invocable.h" +#include "absl/types/span.h" +#include "sharing/internal/api/public_certificate_database.h" + +namespace nearby { + +class FakePublicCertificateDb + : public nearby::sharing::api::PublicCertificateDatabase { + public: + FakePublicCertificateDb() = default; + ~FakePublicCertificateDb() override = default; + + void Initialize( + absl::AnyInvocable< + void(nearby::sharing::api::PublicCertificateDatabase::InitStatus) &&> + callback) override; + void LoadEntries( + absl::AnyInvocable< + void(bool, std::unique_ptr>) &&> + callback) override; + void AddCertificates( + absl::Span certificates, + absl::AnyInvocable callback) override; + void RemoveCertificatesById( + std::vector ids_to_remove, + absl::AnyInvocable callback) override; + void Destroy(absl::AnyInvocable callback) override; + + absl::flat_hash_map + GetCertificatesMap() { + return entries_; + } + + private: + absl::flat_hash_map + entries_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_PUBLIC_CERTIFICATE_DB_H_ diff --git a/sharing/internal/test/fake_shell.h b/sharing/internal/test/fake_shell.h new file mode 100644 index 00000000..5c426b2e --- /dev/null +++ b/sharing/internal/test/fake_shell.h @@ -0,0 +1,60 @@ +// Copyright 2022 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_SHELL_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_SHELL_H_ + +#include // NOLINT(build/c++17) +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "sharing/internal/api/shell.h" +#include "sharing/internal/public/logging.h" + +namespace nearby { + +class FakeShell : public api::Shell { + public: + FakeShell() = default; + + // Open file by application. The mock method doesn't use the path + // parameter. The callback result is controlled by return_error_. + void Open(const std::filesystem::path& path, + std::function callback) override { + if (!std::filesystem::exists(path)) { + NL_LOG(WARNING) << "the path " << path << " is not existed."; + } + + if (return_error_) { + std::move(callback)(absl::UnknownError(absl::StrCat("error code:", 12))); + return; + } + + std::move(callback)(absl::OkStatus()); + } + + // Mock methods. + void set_return_error(bool return_error) { return_error_ = return_error; } + + private: + bool return_error_ = false; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_SHELL_H_ diff --git a/sharing/internal/test/fake_shell_test.cc b/sharing/internal/test/fake_shell_test.cc new file mode 100644 index 00000000..820f0315 --- /dev/null +++ b/sharing/internal/test/fake_shell_test.cc @@ -0,0 +1,42 @@ +// Copyright 2022 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 "sharing/internal/test/fake_shell.h" + +#include // NOLINT(build/c++17) +#include + +#include "gtest/gtest.h" +#include "absl/status/status.h" + +namespace nearby { +namespace { + +TEST(FakeShell, Open) { + FakeShell shell; + absl::Status result; + shell.Open(std::filesystem::temp_directory_path(), + [&](absl::Status status) { result = status; }); + EXPECT_TRUE(result.ok()); +} + +TEST(FakeShell, OpenFailed) { + FakeShell shell; + shell.set_return_error(true); + absl::Status result; + shell.Open("c:\\windows", [&](absl::Status status) { result = status; }); +} + +} // namespace +} // namespace nearby diff --git a/sharing/internal/test/fake_wifi_adapter.h b/sharing/internal/test/fake_wifi_adapter.h new file mode 100644 index 00000000..51d1ee01 --- /dev/null +++ b/sharing/internal/test/fake_wifi_adapter.h @@ -0,0 +1,125 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_H_ + +#include +#include +#include + +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "internal/base/observer_list.h" +#include "sharing/internal/api/wifi_adapter.h" + +namespace nearby { + +class FakeWifiAdapter : public sharing::api::WifiAdapter { + public: + FakeWifiAdapter() { + num_present_received_ = 0; + num_powered_received_ = 0; + } + + ~FakeWifiAdapter() override = default; + + bool IsPresent() const override { return is_present_; } + + bool IsPowered() const override { + // If the Wi-Fi adapter is not present, return false for power status. + if (!is_present_) { + return false; + } + + return is_powered_; + } + + sharing::api::WifiAdapter::PermissionStatus GetOsPermissionStatus() + const override { + return sharing::api::WifiAdapter::PermissionStatus::kAllowed; + } + + void SetPowered(bool powered, std::function success_callback, + std::function error_callback) override { + success_callback(); + } + + std::optional GetAdapterId() const override { return "nearby"; } + + void AddObserver(Observer* observer) override { + observer_list_.AddObserver(observer); + } + void RemoveObserver(Observer* observer) override { + observer_list_.RemoveObserver(observer); + } + bool HasObserver(Observer* observer) override { + return observer_list_.HasObserver(observer); + } + + void JoinNetwork(absl::string_view ssid, absl::string_view password, + std::function callback) override { + callback(absl::OkStatus()); + } + + // Mock OS Wi-Fi adapter presence state changed events + void ReceivedAdapterPresentChangedFromOs(bool present) { + num_present_received_ += 1; + + bool was_present = IsPresent(); + bool is_present = present; + + // Only trigger when state of presence changes values + if (was_present != is_present) { + is_present_ = is_present; + for (Observer* observer : observer_list_.GetObservers()) { + if (observer != nullptr) { + observer->AdapterPresentChanged(this, is_present_); + } + } + } + } + + // Mock OS Wi-Fi adapter powered state changed events + void ReceivedAdapterPoweredChangedFromOs(bool powered) { + num_powered_received_ += 1; + + bool was_powered = IsPowered(); + bool is_powered = powered; + + // Only trigger when state of power changes values + if (was_powered != is_powered) { + is_powered_ = is_powered; + for (Observer* observer : observer_list_.GetObservers()) { + if (observer != nullptr) { + observer->AdapterPoweredChanged(this, is_powered_); + } + } + } + } + + int GetNumPresentReceivedFromOS() { return num_present_received_; } + int GetNumPoweredReceivedFromOS() { return num_powered_received_; } + + private: + ObserverList observer_list_; + bool is_present_ = true; + bool is_powered_ = true; + int num_present_received_; + int num_powered_received_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_H_ diff --git a/sharing/internal/test/fake_wifi_adapter_observer.h b/sharing/internal/test/fake_wifi_adapter_observer.h new file mode 100644 index 00000000..c7f9aef1 --- /dev/null +++ b/sharing/internal/test/fake_wifi_adapter_observer.h @@ -0,0 +1,61 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_OBSERVER_H_ +#define THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_OBSERVER_H_ + +#include "sharing/internal/api/wifi_adapter.h" + +namespace nearby { + +class FakeWifiAdapterObserver : public sharing::api::WifiAdapter::Observer { + public: + explicit FakeWifiAdapterObserver(sharing::api::WifiAdapter* adapter) { + adapter_ = adapter; + num_adapter_present_changed_ = 0; + num_adapter_powered_changed_ = 0; + } + + void AdapterPresentChanged(sharing::api::WifiAdapter* adapter, + bool present) override { + if (adapter == adapter_) { + observed_present_value_ = present; + num_adapter_present_changed_ += 1; + } + } + + void AdapterPoweredChanged(nearby::sharing::api::WifiAdapter* adapter, + bool powered) override { + if (adapter == adapter_) { + observed_powered_value_ = powered; + num_adapter_powered_changed_ += 1; + } + } + bool GetObservedPresentValue() { return observed_present_value_; } + bool GetObservedPoweredValue() { return observed_powered_value_; } + + int GetNumAdapterPresentChanged() { return num_adapter_present_changed_; } + int GetNumAdapterPoweredChanged() { return num_adapter_powered_changed_; } + + private: + sharing::api::WifiAdapter* adapter_; + bool observed_present_value_ = true; + bool observed_powered_value_ = true; + int num_adapter_present_changed_; + int num_adapter_powered_changed_; +}; + +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_INTERNAL_TEST_FAKE_WIFI_ADAPTER_OBSERVER_H_ diff --git a/sharing/internal/test/fake_wifi_adapter_test.cc b/sharing/internal/test/fake_wifi_adapter_test.cc new file mode 100644 index 00000000..770f4391 --- /dev/null +++ b/sharing/internal/test/fake_wifi_adapter_test.cc @@ -0,0 +1,162 @@ +// Copyright 2023 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 "sharing/internal/test/fake_wifi_adapter.h" + +#include +#include + +#include "gtest/gtest.h" +#include "sharing/internal/api/wifi_adapter.h" +#include "sharing/internal/test/fake_wifi_adapter_observer.h" + +namespace nearby { +namespace { + +TEST(FakeWifiAdapter, IsPresentReturnsTrueByDefault) { + FakeWifiAdapter fake_wifi_adapter; + EXPECT_TRUE(fake_wifi_adapter.IsPresent()); +} + +TEST(FakeWifiAdapter, IsPoweredReturnsTrueByDefault) { + FakeWifiAdapter fake_wifi_adapter; + EXPECT_TRUE(fake_wifi_adapter.IsPowered()); +} + +TEST(FakeWifiAdapter, GetOSPermissionStatusReturnsAllowedByDefault) { + FakeWifiAdapter fake_wifi_adapter; + EXPECT_EQ(fake_wifi_adapter.GetOsPermissionStatus(), + sharing::api::WifiAdapter::PermissionStatus::kAllowed); +} + +TEST(FakeWifiAdapter, SetPoweredRunsSuccessCallback) { + bool powered_on; + std::function success_callback = [&powered_on]() { + powered_on = true; + }; + std::function error_callback = [&powered_on]() { + powered_on = false; + }; + FakeWifiAdapter fake_wifi_adapter; + fake_wifi_adapter.SetPowered(/*powered=*/true, success_callback, + error_callback); + EXPECT_TRUE(powered_on); +} + +TEST(FakeWifiAdapter, GetAdapterIdReturnsNearbyByDefault) { + FakeWifiAdapter fake_wifi_adapter; + EXPECT_EQ(fake_wifi_adapter.GetAdapterId(), "nearby"); +} + +TEST(FakeWifiAdapter, HasObserverReturnsTrueAfterAddingObserver) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + fake_wifi_adapter.AddObserver(&fake_observer); + EXPECT_TRUE(fake_wifi_adapter.HasObserver(&fake_observer)); +} + +TEST(FakeWifiAdapter, HasObserverReturnsFalseAfterRemovingObserver) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + + fake_wifi_adapter.AddObserver(&fake_observer); + EXPECT_TRUE(fake_wifi_adapter.HasObserver(&fake_observer)); + + fake_wifi_adapter.RemoveObserver(&fake_observer); + EXPECT_FALSE(fake_wifi_adapter.HasObserver(&fake_observer)); +} + +TEST(FakeWifiAdapter, HasObserver) { + FakeWifiAdapter fake_wifi_adapter; + + FakeWifiAdapterObserver fake_observer_1(&fake_wifi_adapter); + FakeWifiAdapterObserver fake_observer_2(&fake_wifi_adapter); + + fake_wifi_adapter.AddObserver(&fake_observer_1); + + EXPECT_TRUE(fake_wifi_adapter.HasObserver(&fake_observer_1)); + EXPECT_FALSE(fake_wifi_adapter.HasObserver(&fake_observer_2)); +} + +TEST(FakeWifiAdapter, AdapterPresentChanged) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + fake_wifi_adapter.AddObserver(&fake_observer); + + // Mocking OS adapter presence changed events (enabled -> disabled/unplugged) + fake_wifi_adapter.ReceivedAdapterPresentChangedFromOs(/*present=*/false); + EXPECT_FALSE(fake_observer.GetObservedPresentValue()); +} + +TEST(FakeWifiAdapter, AdapterPoweredChanged) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + + fake_wifi_adapter.AddObserver(&fake_observer); + + // Mocking OS adapter powered changed events (on -> off) + fake_wifi_adapter.ReceivedAdapterPoweredChangedFromOs(/*powered=*/false); + EXPECT_FALSE(fake_observer.GetObservedPoweredValue()); +} + +TEST(FakeWifiAdapter, RepeatedAdapterPresentChanged) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + + fake_wifi_adapter.AddObserver(&fake_observer); + + // Mocking first OS adapter present changed event (enabled -> + // disabled/unplugged) + fake_wifi_adapter.ReceivedAdapterPresentChangedFromOs(/*present=*/false); + + EXPECT_EQ(fake_wifi_adapter.GetNumPresentReceivedFromOS(), 1); + EXPECT_EQ(fake_observer.GetNumAdapterPresentChanged(), 1); + + // Mocking second OS adapter present changed event (enabled -> + // disabled/unplugged) + fake_wifi_adapter.ReceivedAdapterPresentChangedFromOs(/*present=*/false); + + // Since it is a repeated event, do not inform observers + // i.e. observers have still only updated the state change once + EXPECT_EQ(fake_wifi_adapter.GetNumPresentReceivedFromOS(), 2); + EXPECT_EQ(fake_observer.GetNumAdapterPresentChanged(), 1); + + EXPECT_FALSE(fake_observer.GetObservedPresentValue()); +} + +TEST(FakeWifiAdapter, RepeatedAdapterPoweredChanged) { + FakeWifiAdapter fake_wifi_adapter; + FakeWifiAdapterObserver fake_observer(&fake_wifi_adapter); + + fake_wifi_adapter.AddObserver(&fake_observer); + + // Mocking first OS adapter powered changed event (on -> off) + fake_wifi_adapter.ReceivedAdapterPoweredChangedFromOs(/*powered=*/false); + + EXPECT_EQ(fake_wifi_adapter.GetNumPoweredReceivedFromOS(), 1); + EXPECT_EQ(fake_observer.GetNumAdapterPoweredChanged(), 1); + + // Mocking second OS adapter powered changed event (on -> off) + fake_wifi_adapter.ReceivedAdapterPoweredChangedFromOs(/*powered=*/false); + + // Since it is a repeated event, do not inform observers + // i.e. observers have still only updated the state change once + EXPECT_EQ(fake_wifi_adapter.GetNumPoweredReceivedFromOS(), 2); + EXPECT_EQ(fake_observer.GetNumAdapterPoweredChanged(), 1); + + EXPECT_FALSE(fake_observer.GetObservedPoweredValue()); +} + +} // namespace +} // namespace nearby diff --git a/sharing/scheduling/BUILD b/sharing/scheduling/BUILD new file mode 100644 index 00000000..00a381bf --- /dev/null +++ b/sharing/scheduling/BUILD @@ -0,0 +1,106 @@ +# Copyright 2024 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. + +licenses(["notice"]) + +cc_library( + name = "format", + srcs = ["format.cc"], + hdrs = ["format.h"], + deps = [ + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "scheduling", + srcs = [ + "nearby_share_expiration_scheduler.cc", + "nearby_share_on_demand_scheduler.cc", + "nearby_share_periodic_scheduler.cc", + "nearby_share_scheduler.cc", + "nearby_share_scheduler_base.cc", + "nearby_share_scheduler_factory.cc", + "nearby_share_scheduler_fields.h", + "nearby_share_scheduler_utils.cc", + ], + hdrs = [ + "nearby_share_expiration_scheduler.h", + "nearby_share_on_demand_scheduler.h", + "nearby_share_periodic_scheduler.h", + "nearby_share_scheduler.h", + "nearby_share_scheduler_base.h", + "nearby_share_scheduler_factory.h", + "nearby_share_scheduler_utils.h", + ], + visibility = ["//visibility:public"], + deps = [ + ":format", + "//sharing/internal/api:platform", + "//sharing/internal/public:logging", + "//sharing/internal/public:types", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "test_support", + testonly = True, + srcs = [ + "fake_nearby_share_scheduler.cc", + "fake_nearby_share_scheduler_factory.cc", + ], + hdrs = [ + "fake_nearby_share_scheduler.h", + "fake_nearby_share_scheduler_factory.h", + ], + visibility = ["//visibility:public"], + deps = [ + ":scheduling", + "//internal/platform:types", + "//sharing/internal/api:platform", + "//sharing/internal/public:logging", + "//sharing/internal/public:types", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + ], +) + +cc_test( + name = "scheduling_test", + srcs = [ + "nearby_share_expiration_scheduler_test.cc", + "nearby_share_on_demand_scheduler_test.cc", + "nearby_share_periodic_scheduler_test.cc", + "nearby_share_scheduler_base_test.cc", + "nearby_share_scheduler_fields.h", + "nearby_share_scheduler_utils_test.cc", + ], + deps = [ + ":scheduling", + "//internal/platform/implementation/g3", # fixdeps: keep + "//internal/test", + "//sharing/internal/api:platform", + "//sharing/internal/public:types", + "//sharing/internal/test:nearby_test", + "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/sharing/scheduling/fake_nearby_share_scheduler.cc b/sharing/scheduling/fake_nearby_share_scheduler.cc new file mode 100644 index 00000000..8041d73a --- /dev/null +++ b/sharing/scheduling/fake_nearby_share_scheduler.cc @@ -0,0 +1,94 @@ +// Copyright 2021 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 "sharing/scheduling/fake_nearby_share_scheduler.h" + +#include + +#include +#include +#include + +#include "absl/time/time.h" +#include "sharing/internal/public/logging.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { + +FakeNearbyShareScheduler::FakeNearbyShareScheduler(OnRequestCallback callback) + : NearbyShareScheduler(std::move(callback)) {} + +FakeNearbyShareScheduler::~FakeNearbyShareScheduler() = default; + +void FakeNearbyShareScheduler::MakeImmediateRequest() { + ++num_immediate_requests_; +} + +void FakeNearbyShareScheduler::HandleResult(bool success) { + handled_results_.push_back(success); +} + +void FakeNearbyShareScheduler::Reschedule() { ++num_reschedule_calls_; } + +std::optional FakeNearbyShareScheduler::GetLastSuccessTime() const { + return last_success_time_; +} + +std::optional +FakeNearbyShareScheduler::GetTimeUntilNextRequest() const { + return time_until_next_request_; +} + +bool FakeNearbyShareScheduler::IsWaitingForResult() const { + return is_waiting_for_result_; +} + +size_t FakeNearbyShareScheduler::GetNumConsecutiveFailures() const { + return num_consecutive_failures_; +} + +void FakeNearbyShareScheduler::OnStart() { + can_invoke_request_callback_ = true; +} + +void FakeNearbyShareScheduler::OnStop() { + can_invoke_request_callback_ = false; +} + +void FakeNearbyShareScheduler::InvokeRequestCallback() { + NL_DCHECK(can_invoke_request_callback_); + NotifyOfRequest(); +} + +void FakeNearbyShareScheduler::SetLastSuccessTime( + std::optional time) { + last_success_time_ = time; +} + +void FakeNearbyShareScheduler::SetTimeUntilNextRequest( + std::optional time_delta) { + time_until_next_request_ = time_delta; +} + +void FakeNearbyShareScheduler::SetIsWaitingForResult(bool is_waiting) { + is_waiting_for_result_ = is_waiting; +} + +void FakeNearbyShareScheduler::SetNumConsecutiveFailures(size_t num_failures) { + num_consecutive_failures_ = num_failures; +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/fake_nearby_share_scheduler.h b/sharing/scheduling/fake_nearby_share_scheduler.h new file mode 100644 index 00000000..78d5cd7d --- /dev/null +++ b/sharing/scheduling/fake_nearby_share_scheduler.h @@ -0,0 +1,76 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_H_ + +#include + +#include +#include + +#include "absl/time/time.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { + +// A fake implementation of NearbyShareScheduler that allows the user to set all +// scheduling data. It tracks the number of immediate requests and the handled +// results. The on-request callback can be invoked using +// InvokeRequestCallback(). +class FakeNearbyShareScheduler : public NearbyShareScheduler { + public: + explicit FakeNearbyShareScheduler(OnRequestCallback callback); + ~FakeNearbyShareScheduler() override; + + // NearbyShareScheduler: + void MakeImmediateRequest() override; + void HandleResult(bool success) override; + void Reschedule() override; + std::optional GetLastSuccessTime() const override; + std::optional GetTimeUntilNextRequest() const override; + bool IsWaitingForResult() const override; + size_t GetNumConsecutiveFailures() const override; + + void SetLastSuccessTime(std::optional time); + void SetTimeUntilNextRequest(std::optional time_delta); + void SetIsWaitingForResult(bool is_waiting); + void SetNumConsecutiveFailures(size_t num_failures); + + void InvokeRequestCallback(); + + size_t num_immediate_requests() const { return num_immediate_requests_; } + size_t num_reschedule_calls() const { return num_reschedule_calls_; } + const std::vector& handled_results() const { return handled_results_; } + + private: + // NearbyShareScheduler: + void OnStart() override; + void OnStop() override; + + bool can_invoke_request_callback_ = false; + size_t num_immediate_requests_ = 0; + size_t num_reschedule_calls_ = 0; + std::vector handled_results_; + std::optional last_success_time_; + std::optional time_until_next_request_; + bool is_waiting_for_result_ = false; + size_t num_consecutive_failures_ = 0; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_H_ diff --git a/sharing/scheduling/fake_nearby_share_scheduler_factory.cc b/sharing/scheduling/fake_nearby_share_scheduler_factory.cc new file mode 100644 index 00000000..9f51215d --- /dev/null +++ b/sharing/scheduling/fake_nearby_share_scheduler_factory.cc @@ -0,0 +1,124 @@ +// Copyright 2021 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 "sharing/scheduling/fake_nearby_share_scheduler_factory.h" + +#include +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "internal/platform/clock.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/fake_nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_expiration_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { + +using ::nearby::sharing::api::PreferenceManager; + +FakeNearbyShareSchedulerFactory::ExpirationInstance::ExpirationInstance( + PreferenceManager& pref_manager, const nearby::Clock* c) + : preference_manager(pref_manager), + clock(c) {} + +FakeNearbyShareSchedulerFactory::ExpirationInstance::ExpirationInstance( + ExpirationInstance&&) = default; + +FakeNearbyShareSchedulerFactory::ExpirationInstance::~ExpirationInstance() = + default; + +FakeNearbyShareSchedulerFactory::OnDemandInstance::OnDemandInstance( + PreferenceManager& pref_manager, const nearby::Clock* c) + : preference_manager(pref_manager), + clock(c) {} + +FakeNearbyShareSchedulerFactory::PeriodicInstance::PeriodicInstance( + PreferenceManager& pref_manager, const nearby::Clock* c) + : preference_manager(pref_manager), + clock(c) {} + +FakeNearbyShareSchedulerFactory::FakeNearbyShareSchedulerFactory() = default; + +FakeNearbyShareSchedulerFactory::~FakeNearbyShareSchedulerFactory() = default; + +std::unique_ptr +FakeNearbyShareSchedulerFactory::CreateExpirationSchedulerInstance( + Context* context, PreferenceManager& preference_manager, + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback on_request_callback) { + ExpirationInstance instance(preference_manager, context->GetClock()); + instance.expiration_time_functor = std::move(expiration_time_functor); + instance.retry_failures = retry_failures; + instance.require_connectivity = require_connectivity; + + auto scheduler = std::make_unique( + std::move(on_request_callback)); + instance.fake_scheduler = scheduler.get(); + + pref_name_to_expiration_instance_.erase(pref_name); + pref_name_to_expiration_instance_.emplace(pref_name, std::move(instance)); + + return scheduler; +} + +std::unique_ptr +FakeNearbyShareSchedulerFactory::CreateOnDemandSchedulerInstance( + Context* context, PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) { + OnDemandInstance instance(preference_manager, context->GetClock()); + instance.retry_failures = retry_failures; + instance.require_connectivity = require_connectivity; + + auto scheduler = + std::make_unique(std::move(callback)); + instance.fake_scheduler = scheduler.get(); + + pref_name_to_on_demand_instance_.erase(pref_name); + pref_name_to_on_demand_instance_.emplace(pref_name, instance); + + return scheduler; +} + +std::unique_ptr +FakeNearbyShareSchedulerFactory::CreatePeriodicSchedulerInstance( + Context* context, PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) { + PeriodicInstance instance(preference_manager, context->GetClock()); + instance.request_period = request_period; + instance.retry_failures = retry_failures; + instance.require_connectivity = require_connectivity; + + auto scheduler = + std::make_unique(std::move(callback)); + instance.fake_scheduler = scheduler.get(); + + pref_name_to_periodic_instance_.erase(pref_name); + pref_name_to_periodic_instance_.emplace(pref_name, instance); + + return scheduler; +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/fake_nearby_share_scheduler_factory.h b/sharing/scheduling/fake_nearby_share_scheduler_factory.h new file mode 100644 index 00000000..f8309598 --- /dev/null +++ b/sharing/scheduling/fake_nearby_share_scheduler_factory.h @@ -0,0 +1,133 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_FACTORY_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_FACTORY_H_ + +#include +#include + +#include "absl/container/flat_hash_map.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/fake_nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_expiration_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_factory.h" + +namespace nearby { +namespace sharing { + +// A fake NearbyShareScheduler factory that creates instances of +// FakeNearbyShareScheduler instead of expiration, on-demand, or periodic +// scheduler. It stores the factory input parameters as well as a raw pointer to +// the fake scheduler for each instance created. +class FakeNearbyShareSchedulerFactory : public NearbyShareSchedulerFactory { + public: + struct ExpirationInstance { + ExpirationInstance( + nearby::sharing::api::PreferenceManager& pref_manager, + const nearby::Clock* c); + ExpirationInstance(ExpirationInstance&&); + ~ExpirationInstance(); + + FakeNearbyShareScheduler* fake_scheduler = nullptr; + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor; + bool retry_failures; + bool require_connectivity; + nearby::sharing::api::PreferenceManager& preference_manager; + const nearby::Clock* const clock; + }; + + struct OnDemandInstance { + OnDemandInstance( + nearby::sharing::api::PreferenceManager& pref_manager, + const nearby::Clock* c); + FakeNearbyShareScheduler* fake_scheduler = nullptr; + bool retry_failures; + bool require_connectivity; + nearby::sharing::api::PreferenceManager& preference_manager; + const nearby::Clock* const clock; + }; + + struct PeriodicInstance { + PeriodicInstance( + nearby::sharing::api::PreferenceManager& pref_manager, + const nearby::Clock* c); + FakeNearbyShareScheduler* fake_scheduler = nullptr; + absl::Duration request_period; + bool retry_failures; + bool require_connectivity; + nearby::sharing::api::PreferenceManager& preference_manager; + const nearby::Clock* const clock; + }; + + FakeNearbyShareSchedulerFactory(); + ~FakeNearbyShareSchedulerFactory() override; + + const absl::flat_hash_map& + pref_name_to_expiration_instance() const { + return pref_name_to_expiration_instance_; + } + + const absl::flat_hash_map& + pref_name_to_on_demand_instance() const { + return pref_name_to_on_demand_instance_; + } + + const absl::flat_hash_map& + pref_name_to_periodic_instance() const { + return pref_name_to_periodic_instance_; + } + + private: + // NearbyShareSchedulerFactory: + std::unique_ptr CreateExpirationSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback on_request_callback) override; + + std::unique_ptr CreateOnDemandSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) override; + + std::unique_ptr CreatePeriodicSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) override; + + absl::flat_hash_map + pref_name_to_expiration_instance_; + absl::flat_hash_map + pref_name_to_on_demand_instance_; + absl::flat_hash_map + pref_name_to_periodic_instance_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FAKE_NEARBY_SHARE_SCHEDULER_FACTORY_H_ diff --git a/sharing/scheduling/format.cc b/sharing/scheduling/format.cc new file mode 100644 index 00000000..671cbf04 --- /dev/null +++ b/sharing/scheduling/format.cc @@ -0,0 +1,35 @@ +// Copyright 2021 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 "sharing/scheduling/format.h" + +#include + +#include "absl/strings/str_format.h" +#include "absl/time/time.h" + +namespace nearby { +namespace utils { + +std::string TimeFormatShortDateAndTimeWithTimeZone(absl::Time time) { + absl::TimeZone tz = absl::LocalTimeZone(); + return absl::FormatTime("%Y%M%D %H:%M:%S %z", time, tz); +} + +std::string TimeDurationFormatWithSeconds(absl::Duration duration) { + return absl::StrFormat("%ds", duration / absl::Seconds(1)); +} + +} // namespace utils +} // namespace nearby diff --git a/sharing/scheduling/format.h b/sharing/scheduling/format.h new file mode 100644 index 00000000..052a42f3 --- /dev/null +++ b/sharing/scheduling/format.h @@ -0,0 +1,31 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FORMAT_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FORMAT_H_ + +#include + +#include "absl/time/time.h" + +namespace nearby { +namespace utils { + +std::string TimeFormatShortDateAndTimeWithTimeZone(absl::Time time); +std::string TimeDurationFormatWithSeconds(absl::Duration duration); + +} // namespace utils +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_FORMAT_H_ diff --git a/sharing/scheduling/nearby_share_expiration_scheduler.cc b/sharing/scheduling/nearby_share_expiration_scheduler.cc new file mode 100644 index 00000000..ecf15720 --- /dev/null +++ b/sharing/scheduling/nearby_share_expiration_scheduler.cc @@ -0,0 +1,55 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_expiration_scheduler.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { +using ::nearby::sharing::api::PreferenceManager; + +NearbyShareExpirationScheduler::NearbyShareExpirationScheduler( + Context* context, PreferenceManager& preference_manager, + ExpirationTimeFunctor expiration_time_functor, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + OnRequestCallback on_request_callback) + : NearbyShareSchedulerBase(context, preference_manager, retry_failures, + require_connectivity, pref_name, + std::move(on_request_callback)), + expiration_time_functor_(std::move(expiration_time_functor)) {} + +NearbyShareExpirationScheduler::~NearbyShareExpirationScheduler() = default; + +std::optional +NearbyShareExpirationScheduler::TimeUntilRecurringRequest( + absl::Time now) const { + std::optional expiration_time = expiration_time_functor_(); + if (!expiration_time.has_value()) return std::nullopt; + + if (*expiration_time <= now) return absl::ZeroDuration(); + + return *expiration_time - now; +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_expiration_scheduler.h b/sharing/scheduling/nearby_share_expiration_scheduler.h new file mode 100644 index 00000000..b752e976 --- /dev/null +++ b/sharing/scheduling/nearby_share_expiration_scheduler.h @@ -0,0 +1,59 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_EXPIRATION_SCHEDULER_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_EXPIRATION_SCHEDULER_H_ + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { + +// A NearbyShareSchedulerBase that schedules recurring tasks based on an +// expiration time provided by the owner. +class NearbyShareExpirationScheduler : public NearbyShareSchedulerBase { + public: + using ExpirationTimeFunctor = std::function()>; + + // |expiration_time_functor|: A function provided by the owner that returns + // the next expiration time. + // See NearbyShareSchedulerBase for a description of other inputs. + NearbyShareExpirationScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + ExpirationTimeFunctor expiration_time_functor, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + OnRequestCallback on_request_callback); + + ~NearbyShareExpirationScheduler() override; + + protected: + std::optional TimeUntilRecurringRequest( + absl::Time now) const override; + + ExpirationTimeFunctor expiration_time_functor_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_EXPIRATION_SCHEDULER_H_ diff --git a/sharing/scheduling/nearby_share_expiration_scheduler_test.cc b/sharing/scheduling/nearby_share_expiration_scheduler_test.cc new file mode 100644 index 00000000..9409d6fb --- /dev/null +++ b/sharing/scheduling/nearby_share_expiration_scheduler_test.cc @@ -0,0 +1,105 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_expiration_scheduler.h" + +#include +#include + +#include "gtest/gtest.h" +#include "absl/time/time.h" +#include "internal/test/fake_clock.h" +#include "sharing/internal/test/fake_context.h" +#include "sharing/internal/test/fake_preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { +namespace { + +const char kTestPrefName[] = "test_pref_name"; +constexpr absl::Duration kTestInitialNow = absl::Hours(2400); +constexpr absl::Duration kTestExpirationTimeFromInitialNow = absl::Minutes(123); + +class NearbyShareExpirationSchedulerTest : public ::testing::Test { + protected: + NearbyShareExpirationSchedulerTest() = default; + ~NearbyShareExpirationSchedulerTest() override = default; + + void SetUp() override { + FastForward(kTestInitialNow); + expiration_time_ = Now() + kTestExpirationTimeFromInitialNow; + + preference_manager_.Remove(kTestPrefName); + + scheduler_ = std::make_unique( + &fake_context_, preference_manager_, callback_, + /*retry_failures=*/true, /*require_connectivity=*/true, kTestPrefName, + nullptr); + } + + absl::Time Now() const { return fake_context_.GetClock()->Now(); } + + // Fast-forwards mock time by |delta| and fires relevant timers. + void FastForward(absl::Duration delta) { + fake_context_.fake_clock()->FastForward(delta); + } + + std::optional expiration_time_; + NearbyShareScheduler* scheduler() { return scheduler_.get(); } + + private: + nearby::FakePreferenceManager preference_manager_; + nearby::FakeContext fake_context_; + std::unique_ptr scheduler_ = nullptr; + NearbyShareExpirationScheduler::ExpirationTimeFunctor callback_ = [&]() { + return expiration_time_; + }; +}; + +TEST_F(NearbyShareExpirationSchedulerTest, ExpirationRequest) { + scheduler()->Start(); + + // Wait 5 minutes to make sure the time to the next request only depends on + // the expiration time and the current time. + FastForward(absl::Minutes(5)); + + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), *expiration_time_ - Now()); +} + +TEST_F(NearbyShareExpirationSchedulerTest, Reschedule) { + scheduler()->Start(); + FastForward(absl::Minutes(5)); + + absl::Duration initial_expected_time_until_next_request = + *expiration_time_ - Now(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + initial_expected_time_until_next_request); + + // The expiration time suddenly changes. + expiration_time_ = *expiration_time_ + absl::Hours(48); + scheduler()->Reschedule(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + initial_expected_time_until_next_request + absl::Hours(48)); +} + +TEST_F(NearbyShareExpirationSchedulerTest, NullExpirationTime) { + expiration_time_.reset(); + scheduler()->Start(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), std::nullopt); +} + +} // namespace +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_on_demand_scheduler.cc b/sharing/scheduling/nearby_share_on_demand_scheduler.cc new file mode 100644 index 00000000..bb17c93e --- /dev/null +++ b/sharing/scheduling/nearby_share_on_demand_scheduler.cc @@ -0,0 +1,47 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_on_demand_scheduler.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { +using ::nearby::sharing::api::PreferenceManager; + +NearbyShareOnDemandScheduler::NearbyShareOnDemandScheduler( + Context* context, PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + OnRequestCallback callback) + : NearbyShareSchedulerBase(context, preference_manager, retry_failures, + require_connectivity, pref_name, + std::move(callback)) {} + +NearbyShareOnDemandScheduler::~NearbyShareOnDemandScheduler() = default; + +std::optional +NearbyShareOnDemandScheduler::TimeUntilRecurringRequest(absl::Time now) const { + return std::nullopt; +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_on_demand_scheduler.h b/sharing/scheduling/nearby_share_on_demand_scheduler.h new file mode 100644 index 00000000..ee5a3645 --- /dev/null +++ b/sharing/scheduling/nearby_share_on_demand_scheduler.h @@ -0,0 +1,51 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_ON_DEMAND_SCHEDULER_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_ON_DEMAND_SCHEDULER_H_ + +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { + +// A NearbyShareSchedulerBase that does not schedule recurring tasks. +class NearbyShareOnDemandScheduler : public NearbyShareSchedulerBase { + public: + // See NearbyShareSchedulerBase for a description of inputs. + NearbyShareOnDemandScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, OnRequestCallback callback); + + ~NearbyShareOnDemandScheduler() override; + + private: + // Return absl::nullopt so as not to schedule recurring requests. + std::optional TimeUntilRecurringRequest( + absl::Time now) const override; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_ON_DEMAND_SCHEDULER_H_ diff --git a/sharing/scheduling/nearby_share_on_demand_scheduler_test.cc b/sharing/scheduling/nearby_share_on_demand_scheduler_test.cc new file mode 100644 index 00000000..93c0a21a --- /dev/null +++ b/sharing/scheduling/nearby_share_on_demand_scheduler_test.cc @@ -0,0 +1,59 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_on_demand_scheduler.h" + +#include + +#include "gtest/gtest.h" +#include "sharing/internal/test/fake_context.h" +#include "sharing/internal/test/fake_preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { +namespace { + +const char kTestPrefName[] = "test_pref_name"; + +class NearbyShareOnDemandSchedulerTest : public ::testing::Test { + protected: + NearbyShareOnDemandSchedulerTest() = default; + ~NearbyShareOnDemandSchedulerTest() override = default; + + void SetUp() override { + preference_manager_.Remove(kTestPrefName); + + scheduler_ = std::make_unique( + &fake_context_, preference_manager_, + /*retry_failures=*/true, /*require_connectivity=*/true, kTestPrefName, + nullptr); + } + + NearbyShareScheduler* scheduler() { return scheduler_.get(); } + + private: + nearby::FakePreferenceManager preference_manager_; + FakeContext fake_context_; + std::unique_ptr scheduler_; +}; + +TEST_F(NearbyShareOnDemandSchedulerTest, NoRecurringRequest) { + scheduler()->Start(); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); +} + +} // namespace +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_periodic_scheduler.cc b/sharing/scheduling/nearby_share_periodic_scheduler.cc new file mode 100644 index 00000000..a32e229e --- /dev/null +++ b/sharing/scheduling/nearby_share_periodic_scheduler.cc @@ -0,0 +1,58 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_periodic_scheduler.h" + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { +using ::nearby::sharing::api::PreferenceManager; + +NearbySharePeriodicScheduler::NearbySharePeriodicScheduler( + Context* context, PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + OnRequestCallback callback) + : NearbyShareSchedulerBase(context, preference_manager, retry_failures, + require_connectivity, pref_name, + std::move(callback)), + request_period_(request_period) {} + +NearbySharePeriodicScheduler::~NearbySharePeriodicScheduler() = default; + +std::optional +NearbySharePeriodicScheduler::TimeUntilRecurringRequest(absl::Time now) const { + std::optional last_success_time = GetLastSuccessTime(); + + // Immediately run a first-time request. + if (!last_success_time.has_value()) return absl::ZeroDuration(); + + absl::Duration time_elapsed_since_last_success = now - *last_success_time; + + return std::max(absl::ZeroDuration(), + request_period_ - time_elapsed_since_last_success); +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_periodic_scheduler.h b/sharing/scheduling/nearby_share_periodic_scheduler.h new file mode 100644 index 00000000..82d3b465 --- /dev/null +++ b/sharing/scheduling/nearby_share_periodic_scheduler.h @@ -0,0 +1,59 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_PERIODIC_SCHEDULER_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_PERIODIC_SCHEDULER_H_ + +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_base.h" + +namespace nearby { +namespace sharing { + +// A NearbyShareSchedulerBase that schedules periodic tasks at fixed intervals. +// Immediate requests and/or failure retries can interrupt this pattern. The +// periodic task is always updated to run a fixed delay after the last +// successful request. +class NearbySharePeriodicScheduler : public NearbyShareSchedulerBase { + public: + // |request_period|: The fixed delay between periodic requests. + // See NearbyShareSchedulerBase for a description of other inputs. + NearbySharePeriodicScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + OnRequestCallback callback); + + ~NearbySharePeriodicScheduler() override; + + private: + // Returns the time until the next periodic request using the time since + // the last success. Immediately runs a first-time periodic request. + std::optional TimeUntilRecurringRequest( + absl::Time now) const override; + + absl::Duration request_period_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_PERIODIC_SCHEDULER_H_ diff --git a/sharing/scheduling/nearby_share_periodic_scheduler_test.cc b/sharing/scheduling/nearby_share_periodic_scheduler_test.cc new file mode 100644 index 00000000..58514b9d --- /dev/null +++ b/sharing/scheduling/nearby_share_periodic_scheduler_test.cc @@ -0,0 +1,86 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_periodic_scheduler.h" + +#include +#include + +#include "gtest/gtest.h" +#include "absl/time/time.h" +#include "internal/test/fake_clock.h" +#include "sharing/internal/test/fake_context.h" +#include "sharing/internal/test/fake_preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { +namespace { + +const char kTestPrefName[] = "test_pref_name"; +constexpr absl::Duration kTestRequestPeriod = absl::Minutes(123); + +class NearbySharePeriodicSchedulerTest : public ::testing::Test { + protected: + NearbySharePeriodicSchedulerTest() = default; + ~NearbySharePeriodicSchedulerTest() override = default; + + void SetUp() override { + preference_manager_.Remove(kTestPrefName); + + scheduler_ = std::make_unique( + &fake_context_, preference_manager_, kTestRequestPeriod, + /*retry_failures=*/true, + /*require_connectivity=*/true, kTestPrefName, nullptr); + } + + absl::Time Now() const { return fake_context_.GetClock()->Now(); } + + // Fast-forwards mock time by |delta| and fires relevant timers. + void FastForward(absl::Duration delta) { + fake_context_.fake_clock()->FastForward(delta); + } + + NearbyShareScheduler* scheduler() { return scheduler_.get(); } + + private: + nearby::FakePreferenceManager preference_manager_; + FakeContext fake_context_; + std::unique_ptr scheduler_; +}; + +TEST_F(NearbySharePeriodicSchedulerTest, PeriodicRequest) { + // Set Now() to something nontrivial. + FastForward(absl::Hours(2400)); + + // Immediately runs a first-time periodic request. + scheduler()->Start(); + std::optional time_until_next_request = + scheduler()->GetTimeUntilNextRequest(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), absl::ZeroDuration()); + FastForward(*time_until_next_request); + scheduler()->HandleResult(/*success=*/true); + EXPECT_EQ(scheduler()->GetLastSuccessTime(), Now()); + + // Wait 1 minute since the last success. + absl::Duration elapsed_time = absl::Minutes(1); + FastForward(elapsed_time); + + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + kTestRequestPeriod - elapsed_time); +} + +} // namespace +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_scheduler.cc b/sharing/scheduling/nearby_share_scheduler.cc new file mode 100644 index 00000000..5932feef --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler.cc @@ -0,0 +1,45 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_scheduler.h" + +#include +#include + +namespace nearby { +namespace sharing { + +NearbyShareScheduler::NearbyShareScheduler(OnRequestCallback callback) + : callback_(std::move(callback)) {} + +NearbyShareScheduler::~NearbyShareScheduler() = default; + +void NearbyShareScheduler::Start() { + is_running_ = true; + OnStart(); +} + +void NearbyShareScheduler::Stop() { + is_running_ = false; + OnStop(); +} + +void NearbyShareScheduler::NotifyOfRequest() { + if (callback_ != nullptr) { + callback_(); + } +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_scheduler.h b/sharing/scheduling/nearby_share_scheduler.h new file mode 100644 index 00000000..e86b6458 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler.h @@ -0,0 +1,91 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_H_ + +#include + +#include +#include + +#include "absl/time/time.h" + +namespace nearby { +namespace sharing { + +// Schedules tasks and alerts the owner when a request is ready. Scheduling +// begins after Start() is called, and scheduling is stopped via Stop(). +// +// An immediate request can be made, bypassing any current scheduling, via +// MakeImmediateRequest(). When a request attempt has completed--successfully +// or not--the owner should invoke HandleResult() so the scheduler can process +// the attempt outcomes and schedule future attempts if necessary. +class NearbyShareScheduler { + public: + using OnRequestCallback = std::function; + + explicit NearbyShareScheduler(OnRequestCallback callback); + virtual ~NearbyShareScheduler(); + + void Start(); + void Stop(); + bool is_running() const { return is_running_; } + + // Make a request that runs as soon as possible. + virtual void MakeImmediateRequest() = 0; + + // Processes the result of the previous request. Method to be called by the + // owner when the request is finished. The timer for the next request is + // automatically scheduled. + virtual void HandleResult(bool success) = 0; + + // Recomputes the time until the next request, using GetTimeUntilNextRequest() + // as the source of truth. This method is essentially idempotent. NOTE: This + // method should rarely need to be called. + virtual void Reschedule() = 0; + + // Returns the time of the last known successful request. If no request has + // succeeded, absl::nullopt is returned. + virtual std::optional GetLastSuccessTime() const = 0; + + // Returns the time until the next scheduled request. Returns std::nullopt if + // there is no request scheduled. + virtual std::optional GetTimeUntilNextRequest() const = 0; + + // Returns true after the |callback_| has been alerted of a request but before + // HandleResult() is invoked. + virtual bool IsWaitingForResult() const = 0; + + // The number of times the current request type has failed. + // Once the request succeeds or a fresh request is made--for example, + // via a manual request--this counter is reset. + virtual size_t GetNumConsecutiveFailures() const = 0; + + protected: + virtual void OnStart() = 0; + virtual void OnStop() = 0; + + // Invokes |callback_|, alerting the owner that a request is ready. + void NotifyOfRequest(); + + private: + bool is_running_ = false; + OnRequestCallback callback_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_H_ diff --git a/sharing/scheduling/nearby_share_scheduler_base.cc b/sharing/scheduling/nearby_share_scheduler_base.cc new file mode 100644 index 00000000..656dbf79 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_base.cc @@ -0,0 +1,340 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_scheduler_base.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/strings/substitute.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/internal/public/logging.h" +#include "sharing/scheduling/format.h" +#include "sharing/scheduling/nearby_share_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler_fields.h" + +namespace nearby { +namespace sharing { +namespace { + +using ::nearby::sharing::api::PreferenceManager; + +constexpr absl::Duration kZeroTimeDelta = absl::ZeroDuration(); +constexpr absl::Duration kBaseRetryDelay = absl::Seconds(5); +constexpr absl::Duration kMaxRetryDelay = absl::Hours(1); + +} // namespace + +NearbyShareSchedulerBase::NearbyShareSchedulerBase( + Context* context, PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + OnRequestCallback callback) + : NearbyShareScheduler(std::move(callback)), + connectivity_manager_(context->GetConnectivityManager()), + preference_manager_(preference_manager), + clock_(context->GetClock()), + retry_failures_(retry_failures), + require_connectivity_(require_connectivity), + pref_name_(pref_name) { + timer_ = context->CreateTimer(); + connection_listener_name_ = absl::Substitute( + "scheduler-$0-$1", pref_name_, absl::ToUnixNanos(absl::UnixEpoch())); + + InitializePersistedRequest(); + is_initialized_ = true; + + if (require_connectivity_) { + connectivity_manager_->RegisterConnectionListener( + connection_listener_name_, + [this](nearby::ConnectivityManager::ConnectionType connection_type, + bool is_lan_connected) { + OnConnectionChanged(connection_type); + }); + } +} + +NearbyShareSchedulerBase::~NearbyShareSchedulerBase() { + if (require_connectivity_) { + connectivity_manager_->UnregisterConnectionListener( + connection_listener_name_); + } +} + +void NearbyShareSchedulerBase::MakeImmediateRequest() { + timer_->Stop(); + SetHasPendingImmediateRequest(true); + Reschedule(); +} + +void NearbyShareSchedulerBase::HandleResult(bool success) { + absl::Time now = clock_->Now(); + SetLastAttemptTime(now); + + NL_LOG(INFO) << "Nearby Share scheduler \"" << pref_name_ + << "\" latest attempt " << (success ? "succeeded" : "failed"); + + if (success) { + SetLastSuccessTime(now); + SetNumConsecutiveFailures(0); + } else { + SetNumConsecutiveFailures(GetNumConsecutiveFailures() + 1); + } + + SetIsWaitingForResult(false); + Reschedule(); + PrintSchedulerState(); +} + +void NearbyShareSchedulerBase::Reschedule() { + if (!is_running()) return; + + timer_->Stop(); + + std::optional delay = GetTimeUntilNextRequest(); + if (!delay.has_value()) return; + + int64_t delay_milliseconds = (*delay) / absl::Milliseconds(1); + + timer_->Start(delay_milliseconds, delay_milliseconds, + [this]() { OnTimerFired(); }); +} + +std::optional NearbyShareSchedulerBase::GetLastSuccessTime() const { + std::optional pref_value = + preference_manager_.GetDictionaryInt64Value( + pref_name_, SchedulerFields::kLastSuccessTimeKeyName); + if (!pref_value.has_value()) { + return std::nullopt; + } + return absl::FromUnixNanos(pref_value.value()); +} + +std::optional +NearbyShareSchedulerBase::GetTimeUntilNextRequest() const { + if (!is_running() || IsWaitingForResult()) return std::nullopt; + + if (HasPendingImmediateRequest()) return kZeroTimeDelta; + + absl::Time now = clock_->Now(); + + // Recover from failures using exponential backoff strategy if necessary. + std::optional time_until_retry = TimeUntilRetry(now); + if (time_until_retry) return time_until_retry; + + // Schedule the periodic request if applicable. + return TimeUntilRecurringRequest(now); +} + +bool NearbyShareSchedulerBase::IsWaitingForResult() const { + std::optional pref_value = + preference_manager_.GetDictionaryBooleanValue( + pref_name_, SchedulerFields::kIsWaitingForResultKeyName); + + bool is_waiting = false; + if (pref_value.has_value()) { + is_waiting = pref_value.value(); + } + + if (is_waiting) { + return true; + } + + // The scheduler must be initialized if it is not initialized or has failed. + // This will speed up the data sync when there are issues. + if (!is_initialized_) { + if (GetNumConsecutiveFailures() > 0) { + NL_LOG(WARNING) << ": Run the scheduler " << pref_name_ + << " immediately due to having failed runs."; + return true; + } + } + + return false; +} + +size_t NearbyShareSchedulerBase::GetNumConsecutiveFailures() const { + std::optional pref_value = + preference_manager_.GetDictionaryInt64Value( + pref_name_, SchedulerFields::kNumConsecutiveFailuresKeyName); + + if (!pref_value.has_value()) { + return 0; + } + return pref_value.value(); +} + +void NearbyShareSchedulerBase::OnStart() { + Reschedule(); + NL_LOG(INFO) << "Starting Nearby Share scheduler \"" << pref_name_ << "\""; + PrintSchedulerState(); +} + +void NearbyShareSchedulerBase::OnStop() { timer_->Stop(); } + +void NearbyShareSchedulerBase::OnConnectionChanged( + nearby::ConnectivityManager::ConnectionType connection_type) { + if (connection_type == nearby::ConnectivityManager::ConnectionType::kNone) + return; + + Reschedule(); +} + +std::optional NearbyShareSchedulerBase::GetLastAttemptTime() const { + std::optional pref_value = + preference_manager_.GetDictionaryInt64Value( + pref_name_, SchedulerFields::kLastAttemptTimeKeyName); + if (!pref_value.has_value()) { + return std::nullopt; + } + return absl::FromUnixNanos(pref_value.value()); +} + +bool NearbyShareSchedulerBase::HasPendingImmediateRequest() const { + std::optional pref_value = + preference_manager_.GetDictionaryBooleanValue( + pref_name_, SchedulerFields::kHasPendingImmediateRequestKeyName); + if (!pref_value.has_value()) { + return false; + } + return pref_value.value(); +} + +void NearbyShareSchedulerBase::SetLastAttemptTime( + absl::Time last_attempt_time) { + preference_manager_.SetDictionaryInt64Value( + pref_name_, SchedulerFields::kLastAttemptTimeKeyName, + absl::ToUnixNanos(last_attempt_time)); +} + +void NearbyShareSchedulerBase::SetLastSuccessTime( + absl::Time last_success_time) { + preference_manager_.SetDictionaryInt64Value( + pref_name_, SchedulerFields::kLastSuccessTimeKeyName, + absl::ToUnixNanos(last_success_time)); +} + +void NearbyShareSchedulerBase::SetNumConsecutiveFailures(size_t num_failures) { + preference_manager_.SetDictionaryInt64Value( + pref_name_, SchedulerFields::kNumConsecutiveFailuresKeyName, + num_failures); +} + +void NearbyShareSchedulerBase::SetHasPendingImmediateRequest( + bool has_pending_immediate_request) { + preference_manager_.SetDictionaryBooleanValue( + pref_name_, SchedulerFields::kHasPendingImmediateRequestKeyName, + has_pending_immediate_request); +} + +void NearbyShareSchedulerBase::SetIsWaitingForResult( + bool is_waiting_for_result) { + preference_manager_.SetDictionaryBooleanValue( + pref_name_, SchedulerFields::kIsWaitingForResultKeyName, + is_waiting_for_result); +} + +void NearbyShareSchedulerBase::InitializePersistedRequest() { + if (IsWaitingForResult()) { + SetHasPendingImmediateRequest(true); + SetIsWaitingForResult(false); + } +} + +std::optional NearbyShareSchedulerBase::TimeUntilRetry( + absl::Time now) const { + if (!retry_failures_) return std::nullopt; + + size_t num_failures = GetNumConsecutiveFailures(); + if (num_failures == 0) return std::nullopt; + + // The exponential back off is + // + // base * 2^(num_failures - 1) + // + // up to a fixed maximum retry delay. + absl::Duration delay = + std::min(kMaxRetryDelay, kBaseRetryDelay * (1 << (num_failures - 1))); + + absl::Duration time_elapsed_since_last_attempt = now - *GetLastAttemptTime(); + + return std::max(kZeroTimeDelta, delay - time_elapsed_since_last_attempt); +} + +void NearbyShareSchedulerBase::OnTimerFired() { + NL_DCHECK(is_running()); + if (require_connectivity_ && + (connectivity_manager_->GetConnectionType() == + nearby::ConnectivityManager::ConnectionType::kNone)) { + return; + } + + SetIsWaitingForResult(true); + SetHasPendingImmediateRequest(false); + NotifyOfRequest(); +} + +void NearbyShareSchedulerBase::PrintSchedulerState() const { + std::optional last_attempt_time = GetLastAttemptTime(); + std::optional last_success_time = GetLastSuccessTime(); + std::optional time_until_next_request = + GetTimeUntilNextRequest(); + + std::stringstream ss; + ss << "State of Nearby Share scheduler \"" << pref_name_ << "\":" + << "\n Last attempt time: "; + if (last_attempt_time) { + ss << nearby::utils::TimeFormatShortDateAndTimeWithTimeZone( + *last_attempt_time); + } else { + ss << "Never"; + } + + ss << "\n Last success time: "; + if (last_success_time) { + ss << nearby::utils::TimeFormatShortDateAndTimeWithTimeZone( + *last_success_time); + } else { + ss << "Never"; + } + + ss << "\n Time until next request: "; + if (time_until_next_request) { + std::u16string next_request_delay; + ss << nearby::utils::TimeDurationFormatWithSeconds( + *time_until_next_request); + } else { + ss << "Never"; + } + + ss << "\n Is waiting for result? " << (IsWaitingForResult() ? "Yes" : "No"); + ss << "\n Pending immediate request? " + << (HasPendingImmediateRequest() ? "Yes" : "No"); + ss << "\n Num consecutive failures: " << GetNumConsecutiveFailures(); + + NL_VLOG(1) << ss.str(); +} + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_scheduler_base.h b/sharing/scheduling/nearby_share_scheduler_base.h new file mode 100644 index 00000000..21e57312 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_base.h @@ -0,0 +1,130 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_BASE_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_BASE_H_ + +#include + +#include +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/connectivity_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { + +// A base NearbyShareScheduler implementation that persists scheduling data. +// Requests made before scheduling has started, while another attempt is in +// progress, or while offline are cached and rescheduled as soon as possible. +// Likewise, when the scheduler is stopped or destroyed, scheduling data is +// persisted and restored when the scheduler is restarted or recreated, +// respectively. +// +// If automatic failure retry is enabled, all failed attempts follow an +// exponential backoff retry strategy. +// +// The scheduler waits until the device is online before notifying the owner if +// network connectivity is required. +// +// Derived classes must override TimeUntilRecurringRequest() to establish the +// desired recurring request behavior of the scheduler. +class NearbyShareSchedulerBase : public NearbyShareScheduler { + public: + ~NearbyShareSchedulerBase() override; + + protected: + // |context|: Nearby context, holding nearby common components. + // |retry_failures|: Whether or not automatically retry failures using + // exponential backoff strategy. + // |require_connectivity|: If true, the scheduler will not alert the owner of + // a request until network connectivity is established. + // |pref_name|: The dictionary pref name used to persist scheduling data. Make + // sure to register this pref name before creating the scheduler. + // |callback|: The function invoked to alert the owner that a request is due. + NearbyShareSchedulerBase( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, OnRequestCallback callback); + + // The time to wait until the next regularly recurring request. + virtual std::optional TimeUntilRecurringRequest( + absl::Time now) const = 0; + + // NearbyShareScheduler: + void MakeImmediateRequest() override; + void HandleResult(bool success) override; + void Reschedule() override; + std::optional GetLastSuccessTime() const override; + std::optional GetTimeUntilNextRequest() const override; + bool IsWaitingForResult() const override; + size_t GetNumConsecutiveFailures() const override; + void OnStart() override; + void OnStop() override; + + void OnConnectionChanged( + nearby::ConnectivityManager::ConnectionType connection_type); + + std::optional GetLastAttemptTime() const; + bool HasPendingImmediateRequest() const; + + // Set and persist scheduling data in prefs. + void SetLastAttemptTime(absl::Time last_attempt_time); + void SetLastSuccessTime(absl::Time last_success_time); + void SetNumConsecutiveFailures(size_t num_failures); + void SetHasPendingImmediateRequest(bool has_pending_immediate_request); + void SetIsWaitingForResult(bool is_waiting_for_result); + + // On startup, set a pending immediate request if the pref service indicates + // that there was an in-progress request or a pending immediate request at the + // time of shutdown. + void InitializePersistedRequest(); + + // The amount of time to wait until the next automatic failure retry. Returns + // std::nullopt if there is no failure to retry or if failure retry is not + // enabled for the scheduler. + std::optional TimeUntilRetry(absl::Time now) const; + + // Notifies the owner that a request is ready. Early returns if not online and + // the scheduler requires connectivity; the attempt is rescheduled when + // connectivity is restored. + void OnTimerFired(); + + void PrintSchedulerState() const; + + private: + nearby::ConnectivityManager* const connectivity_manager_; + nearby::sharing::api::PreferenceManager& preference_manager_; + const nearby::Clock* const clock_; + + const bool retry_failures_; + const bool require_connectivity_; + const std::string pref_name_; + bool is_initialized_ = false; + std::string connection_listener_name_; + + std::unique_ptr timer_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_BASE_H_ diff --git a/sharing/scheduling/nearby_share_scheduler_base_test.cc b/sharing/scheduling/nearby_share_scheduler_base_test.cc new file mode 100644 index 00000000..c5f50cfb --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_base_test.cc @@ -0,0 +1,409 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_scheduler_base.h" + +#include + +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "internal/test/fake_clock.h" +#include "sharing/internal/test/fake_context.h" +#include "sharing/internal/test/fake_preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { +namespace { + +using ::nearby::sharing::api::PreferenceManager; + +const char kTestPrefName[] = "test_pref_name"; + +constexpr absl::Duration kZeroTimeDuration = absl::ZeroDuration(); +constexpr absl::Duration kBaseRetryDuration = absl::Seconds(5); +constexpr absl::Duration kMaxRetryDuration = absl::Hours(1); + +constexpr absl::Duration kTestTimeUntilRecurringRequest = absl::Minutes(120); + +class NearbyShareSchedulerBaseForTest : public NearbyShareSchedulerBase { + public: + NearbyShareSchedulerBaseForTest( + Context* context, + PreferenceManager& preference_manager, + std::optional time_until_recurring_request, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, OnRequestCallback callback) + : NearbyShareSchedulerBase(context, preference_manager, retry_failures, + require_connectivity, pref_name, + std::move(callback)), + time_until_recurring_request_(time_until_recurring_request) {} + + ~NearbyShareSchedulerBaseForTest() override = default; + + private: + std::optional TimeUntilRecurringRequest( + absl::Time now) const override { + return time_until_recurring_request_; + } + + std::optional time_until_recurring_request_; +}; + +class NearbyShareSchedulerBaseTest : public ::testing::Test { + protected: + NearbyShareSchedulerBaseTest() = default; + + ~NearbyShareSchedulerBaseTest() override = default; + + void SetUp() override { + preference_manager_.Remove(kTestPrefName); + } + + void CreateScheduler( + bool retry_failures, bool require_connectivity, + std::optional time_until_recurring_request = + kTestTimeUntilRecurringRequest) { + scheduler_ = std::make_unique( + &fake_context_, preference_manager_, time_until_recurring_request, + retry_failures, require_connectivity, kTestPrefName, callback_); + } + + void DestroyScheduler() { scheduler_.reset(); } + + void StartScheduling() { + scheduler_->Start(); + EXPECT_TRUE(scheduler_->is_running()); + } + + void StopScheduling() { + scheduler_->Stop(); + EXPECT_FALSE(scheduler_->is_running()); + } + + // Fast-forwards mock time by |delta| and fires relevant timers. + void FastForward(absl::Duration delta) { + fake_context_.fake_clock()->FastForward(delta); + } + + void RunPendingRequest() { + EXPECT_FALSE(scheduler_->IsWaitingForResult()); + std::optional time_until_next_request = + scheduler_->GetTimeUntilNextRequest(); + ASSERT_TRUE(time_until_next_request); + FastForward(*time_until_next_request); + } + + void FinishPendingRequest(bool success) { + EXPECT_TRUE(scheduler_->IsWaitingForResult()); + EXPECT_FALSE(scheduler_->GetTimeUntilNextRequest().has_value()); + size_t num_failures = scheduler_->GetNumConsecutiveFailures(); + std::optional last_success_time = + scheduler_->GetLastSuccessTime(); + scheduler_->HandleResult(success); + EXPECT_FALSE(scheduler_->IsWaitingForResult()); + EXPECT_EQ(scheduler_->GetNumConsecutiveFailures(), + success ? 0 : num_failures + 1); + EXPECT_EQ( + scheduler_->GetLastSuccessTime(), + success ? std::make_optional(Now()) : last_success_time); + } + + absl::Time Now() const { + return fake_context_.GetClock()->Now(); + } + + size_t on_request_call_count() const { return on_request_call_count_; } + NearbyShareScheduler* scheduler() { return scheduler_.get(); } + + private: + nearby::FakePreferenceManager preference_manager_; + nearby::FakeContext fake_context_; + size_t on_request_call_count_ = 0; + std::unique_ptr scheduler_; + NearbyShareScheduler::OnRequestCallback callback_ = [&]() { + ++on_request_call_count_; + }; +}; + +TEST_F(NearbyShareSchedulerBaseTest, ImmediateRequest) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + scheduler()->MakeImmediateRequest(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, RecurringRequest) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + kTestTimeUntilRecurringRequest); + + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + FinishPendingRequest(/*success=*/true); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + kTestTimeUntilRecurringRequest); +} + +TEST_F(NearbyShareSchedulerBaseTest, NoRecurringRequest) { + // The flavor of the schedule does not schedule recurring requests. + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true, + /*time_until_recurring_request=*/std::nullopt); + StartScheduling(); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); + + scheduler()->MakeImmediateRequest(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + FinishPendingRequest(/*success=*/true); + + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); +} + +TEST_F(NearbyShareSchedulerBaseTest, SchedulingNotStarted) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + EXPECT_FALSE(scheduler()->is_running()); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + + // Request remains pending until scheduling starts. + scheduler()->MakeImmediateRequest(); + EXPECT_FALSE(scheduler()->is_running()); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); +} + +TEST_F(NearbyShareSchedulerBaseTest, DoNotRetryFailures) { + CreateScheduler(/*retry_failures=*/false, /*require_connectivity=*/true); + StartScheduling(); + + // Run recurring request. + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + FinishPendingRequest(/*success=*/false); + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), 1u); + + // Failure is not automatically retried; the recurring request is re-scheduled + // instead. + EXPECT_EQ(kTestTimeUntilRecurringRequest, + scheduler()->GetTimeUntilNextRequest()); + + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 2u); + FinishPendingRequest(/*success=*/false); + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), 2u); +} + +TEST_F(NearbyShareSchedulerBaseTest, FailureRetry) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + scheduler()->MakeImmediateRequest(); + + size_t num_failures = 0; + size_t expected_backoff_factor = 1; + do { + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), num_failures); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), num_failures + 1); + FinishPendingRequest(/*success=*/false); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + std::min(kMaxRetryDuration, + kBaseRetryDuration * expected_backoff_factor)); + expected_backoff_factor *= 2; + ++num_failures; + } while (*scheduler()->GetTimeUntilNextRequest() != kMaxRetryDuration); + + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), num_failures + 1); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, + FailureRetry_InterruptWithImmediateAttempt) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + scheduler()->MakeImmediateRequest(); + + size_t num_failures = 0; + size_t expected_backoff_factor = 1; + do { + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), num_failures); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), num_failures + 1); + FinishPendingRequest(/*success=*/false); + EXPECT_EQ(std::min(kMaxRetryDuration, + kBaseRetryDuration * expected_backoff_factor), + scheduler()->GetTimeUntilNextRequest()); + expected_backoff_factor *= 2; + ++num_failures; + } while (num_failures < 3); + + // Interrupt retry schedule with immediate request. On failure, it continues + // the retry strategy using the next backoff. + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), num_failures); + scheduler()->MakeImmediateRequest(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), num_failures + 1); + FinishPendingRequest(/*success=*/false); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), + std::min(kMaxRetryDuration, + kBaseRetryDuration * expected_backoff_factor)); + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), num_failures + 1); +} + +TEST_F(NearbyShareSchedulerBaseTest, StopScheduling_BeforeTimerFires) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + + StopScheduling(); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); + + // Timer is still fired but owner is not notified. + FastForward(kZeroTimeDuration); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); + + // Scheduling restarts and pending task is rescheduled. + StartScheduling(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, StopScheduling_BeforeResultIsHandled) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + + StartScheduling(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + + StopScheduling(); + EXPECT_TRUE(scheduler()->IsWaitingForResult()); + + // Although scheduling is stopped, the result can still be handled. No further + // requests will be scheduled though. + FinishPendingRequest(/*success=*/true); + EXPECT_FALSE(scheduler()->GetTimeUntilNextRequest()); +} + +TEST_F(NearbyShareSchedulerBaseTest, RestoreRequest_InProgress) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + StartScheduling(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + EXPECT_TRUE(scheduler()->IsWaitingForResult()); + DestroyScheduler(); + + // On startup, set a pending immediate request because there was an + // in-progress request at the time of shutdown. + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 2u); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, RestoreRequest_Pending_Immediate) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + DestroyScheduler(); + + // On startup, set a pending immediate request because there was a pending + // immediate request at the time of shutdown. + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), kZeroTimeDuration); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, RestoreRequest_Pending_FailureRetry) { + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + StartScheduling(); + + // Fail three times then destroy scheduler. + for (size_t num_failures = 0; num_failures < 3; ++num_failures) { + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), num_failures + 1); + FinishPendingRequest(/*success=*/false); + } + absl::Duration initial_time_until_next_request = + *scheduler()->GetTimeUntilNextRequest(); + EXPECT_EQ(initial_time_until_next_request, 4 * kBaseRetryDuration); + DestroyScheduler(); + + // 1s elapses while there is no scheduler. When the scheduler is recreated, + // the retry request is rescheduled, accounting for the elapsed time. + absl::Duration elapsed_time = absl::Seconds(1); + FastForward(elapsed_time); + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + EXPECT_FALSE(scheduler()->IsWaitingForResult()); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), absl::Seconds(0)); + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), 3u); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 4u); + FinishPendingRequest(/*success=*/true); +} + +TEST_F(NearbyShareSchedulerBaseTest, RestoreSchedulingData) { + // Succeed immediately, then fail once before destroying the scheduler. + absl::Time expected_last_success_time = Now() + absl::Seconds(100); + FastForward(expected_last_success_time - Now()); + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + scheduler()->MakeImmediateRequest(); + StartScheduling(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 1u); + FinishPendingRequest(/*success=*/true); + scheduler()->MakeImmediateRequest(); + ASSERT_NO_FATAL_FAILURE(RunPendingRequest()); + EXPECT_EQ(on_request_call_count(), 2u); + FinishPendingRequest(/*success=*/false); + DestroyScheduler(); + + CreateScheduler(/*retry_failures=*/true, /*require_connectivity=*/true); + StartScheduling(); + EXPECT_EQ(scheduler()->GetLastSuccessTime(), expected_last_success_time); + EXPECT_EQ(scheduler()->GetTimeUntilNextRequest(), absl::Seconds(0)); + EXPECT_EQ(scheduler()->GetNumConsecutiveFailures(), 1u); +} + +} // namespace +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_scheduler_factory.cc b/sharing/scheduling/nearby_share_scheduler_factory.cc new file mode 100644 index 00000000..4d1bc576 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_factory.cc @@ -0,0 +1,102 @@ +// Copyright 2021 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 "sharing/scheduling/nearby_share_scheduler_factory.h" + +#include +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_expiration_scheduler.h" +#include "sharing/scheduling/nearby_share_on_demand_scheduler.h" +#include "sharing/scheduling/nearby_share_periodic_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { +using ::nearby::sharing::api::PreferenceManager; + +// static +NearbyShareSchedulerFactory* NearbyShareSchedulerFactory::test_factory_ = + nullptr; + +// static +std::unique_ptr +NearbyShareSchedulerFactory::CreateExpirationScheduler( + Context* context, PreferenceManager& preference_manager, + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback on_request_callback) { + if (test_factory_) { + return test_factory_->CreateExpirationSchedulerInstance( + context, preference_manager, std::move(expiration_time_functor), + retry_failures, require_connectivity, pref_name, + std::move(on_request_callback)); + } + + return std::make_unique( + context, preference_manager, std::move(expiration_time_functor), + retry_failures, require_connectivity, pref_name, + std::move(on_request_callback)); +} + +// static +std::unique_ptr +NearbyShareSchedulerFactory::CreateOnDemandScheduler( + Context* context, PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) { + if (test_factory_) { + return test_factory_->CreateOnDemandSchedulerInstance( + context, preference_manager, retry_failures, require_connectivity, + pref_name, std::move(callback)); + } + + return std::make_unique( + context, preference_manager, retry_failures, require_connectivity, + pref_name, std::move(callback)); +} + +// static +std::unique_ptr +NearbyShareSchedulerFactory::CreatePeriodicScheduler( + Context* context, PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) { + if (test_factory_) { + return test_factory_->CreatePeriodicSchedulerInstance( + context, preference_manager, request_period, retry_failures, + require_connectivity, pref_name, std::move(callback)); + } + + return std::make_unique( + context, preference_manager, request_period, retry_failures, + require_connectivity, pref_name, std::move(callback)); +} + +// static +void NearbyShareSchedulerFactory::SetFactoryForTesting( + NearbyShareSchedulerFactory* test_factory) { + test_factory_ = test_factory; +} + +NearbyShareSchedulerFactory::~NearbyShareSchedulerFactory() = default; + +} // namespace sharing +} // namespace nearby diff --git a/sharing/scheduling/nearby_share_scheduler_factory.h b/sharing/scheduling/nearby_share_scheduler_factory.h new file mode 100644 index 00000000..bff24d36 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_factory.h @@ -0,0 +1,96 @@ +// Copyright 2021 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FACTORY_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FACTORY_H_ + +#include + +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/public/context.h" +#include "sharing/scheduling/nearby_share_expiration_scheduler.h" +#include "sharing/scheduling/nearby_share_scheduler.h" + +namespace nearby { +namespace sharing { + +// class PrefService; + +// Used to create instances of NearbyShareExpirationScheduler, +// NearbyShareOnDemandScheduler, and NearbySharePeriodicScheduler. A fake +// factory can also be set for testing purposes. +class NearbyShareSchedulerFactory { + public: + static std::unique_ptr CreateExpirationScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback on_request_callback); + + static std::unique_ptr CreateOnDemandScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback); + + static std::unique_ptr CreatePeriodicScheduler( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback); + + static void SetFactoryForTesting(NearbyShareSchedulerFactory* test_factory); + + protected: + virtual ~NearbyShareSchedulerFactory(); + + virtual std::unique_ptr + CreateExpirationSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + NearbyShareExpirationScheduler::ExpirationTimeFunctor + expiration_time_functor, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback on_request_callback) = 0; + + virtual std::unique_ptr CreateOnDemandSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + bool retry_failures, bool require_connectivity, + absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) = 0; + + virtual std::unique_ptr CreatePeriodicSchedulerInstance( + Context* context, + nearby::sharing::api::PreferenceManager& preference_manager, + absl::Duration request_period, bool retry_failures, + bool require_connectivity, absl::string_view pref_name, + NearbyShareScheduler::OnRequestCallback callback) = 0; + + private: + static NearbyShareSchedulerFactory* test_factory_; +}; + +} // namespace sharing +} // namespace nearby + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FACTORY_H_ diff --git a/sharing/scheduling/nearby_share_scheduler_fields.h b/sharing/scheduling/nearby_share_scheduler_fields.h new file mode 100644 index 00000000..c05d47ae --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_fields.h @@ -0,0 +1,34 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FIELDS_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FIELDS_H_ + +#include "absl/strings/string_view.h" + +namespace nearby::sharing { + +// Field names used in scheduler preference storage. +class SchedulerFields { + public: + static constexpr absl::string_view kLastAttemptTimeKeyName = "a"; + static constexpr absl::string_view kLastSuccessTimeKeyName = "s"; + static constexpr absl::string_view kNumConsecutiveFailuresKeyName = "f"; + static constexpr absl::string_view kHasPendingImmediateRequestKeyName = "p"; + static constexpr absl::string_view kIsWaitingForResultKeyName = "w"; +}; + +} // namespace nearby::sharing + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_FIELDS_H_ diff --git a/sharing/scheduling/nearby_share_scheduler_utils.cc b/sharing/scheduling/nearby_share_scheduler_utils.cc new file mode 100644 index 00000000..a8a5489f --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_utils.cc @@ -0,0 +1,85 @@ +// Copyright 2023 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 "sharing/scheduling/nearby_share_scheduler_utils.h" + +#include +#include +#include +#include +#include +#include + +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler_fields.h" + +namespace nearby::sharing { + +using ::nearby::sharing::api::PreferenceManager; + +std::string ConvertToReadableSchedule(PreferenceManager& preference_manager, + absl::string_view schedule_preference) { + std::string result = "{"; + std::optional attempt_time = + preference_manager.GetDictionaryInt64Value( + schedule_preference, SchedulerFields::kLastAttemptTimeKeyName); + if (attempt_time.has_value()) { + std::time_t local_t = + absl::ToTimeT(absl::FromUnixNanos(attempt_time.value())); + std::tm* local_time = std::localtime(&local_t); + std::stringstream buffer; + buffer << std::put_time(local_time, "%Y-%m-%d %H:%M:%S"); + absl::StrAppendFormat(&result, "attempt_time:%s, ", buffer.str()); + } + std::optional success_time = + preference_manager.GetDictionaryInt64Value( + schedule_preference, SchedulerFields::kLastSuccessTimeKeyName); + if (success_time.has_value()) { + std::time_t local_t = + absl::ToTimeT(absl::FromUnixNanos(success_time.value())); + std::tm* local_time = std::localtime(&local_t); + std::stringstream buffer; + buffer << std::put_time(local_time, "%Y-%m-%d %H:%M:%S"); + absl::StrAppendFormat(&result, "success_time:%s, ", buffer.str()); + } + std::optional failed_count = + preference_manager.GetDictionaryInt64Value( + schedule_preference, SchedulerFields::kNumConsecutiveFailuresKeyName); + if (failed_count.has_value()) { + absl::StrAppendFormat(&result, "failed_count:%d, ", failed_count.value()); + } + std::optional has_pending = + preference_manager.GetDictionaryBooleanValue( + schedule_preference, + SchedulerFields::kHasPendingImmediateRequestKeyName); + if (has_pending.has_value()) { + absl::StrAppendFormat(&result, "has_pending_request:%s, ", + has_pending.value() ? "true" : "false"); + } + std::optional is_waiting = preference_manager.GetDictionaryBooleanValue( + schedule_preference, SchedulerFields::kIsWaitingForResultKeyName); + if (is_waiting.has_value()) { + absl::StrAppendFormat(&result, "is_waiting_for_result:%s", + is_waiting.value() ? "true" : "false"); + } + + absl::StrAppend(&result, "}"); + return result; +} + +} // namespace nearby::sharing diff --git a/sharing/scheduling/nearby_share_scheduler_utils.h b/sharing/scheduling/nearby_share_scheduler_utils.h new file mode 100644 index 00000000..645fde0e --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_utils.h @@ -0,0 +1,32 @@ +// Copyright 2023 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. + +#ifndef THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_UTILS_H_ +#define THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_UTILS_H_ + +#include + +#include "absl/strings/string_view.h" +#include "sharing/internal/api/preference_manager.h" + +namespace nearby::sharing { + +// Converts the schedule preference to a readable string. +std::string ConvertToReadableSchedule( + nearby::sharing::api::PreferenceManager& preference_manager, + absl::string_view schedule_preference); + +} // namespace nearby::sharing + +#endif // THIRD_PARTY_NEARBY_SHARING_SCHEDULING_NEARBY_SHARE_SCHEDULER_UTILS_H_ diff --git a/sharing/scheduling/nearby_share_scheduler_utils_test.cc b/sharing/scheduling/nearby_share_scheduler_utils_test.cc new file mode 100644 index 00000000..5fa95551 --- /dev/null +++ b/sharing/scheduling/nearby_share_scheduler_utils_test.cc @@ -0,0 +1,118 @@ +// Copyright 2023 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 "sharing/scheduling/nearby_share_scheduler_utils.h" + +#include +#include +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/strings/string_view.h" +#include "sharing/internal/api/preference_manager.h" +#include "sharing/internal/test/fake_preference_manager.h" +#include "sharing/scheduling/nearby_share_scheduler_fields.h" + +namespace nearby::sharing { + +using ::nearby::sharing::api::PreferenceManager; +using ::testing::Eq; + +class NearbyShareSchedulerUtilsTest : public ::testing::Test { + protected: + NearbyShareSchedulerUtilsTest() = default; + ~NearbyShareSchedulerUtilsTest() override = default; + + void CreateSchedule(absl::string_view pref_name, + std::optional attempt_time, + std::optional success_time, + std::optional failed_count, + std::optional has_pending, + std::optional is_waiting) { + if (attempt_time.has_value()) { + preference_manager_.SetDictionaryInt64Value( + pref_name, SchedulerFields::kLastAttemptTimeKeyName, + attempt_time.value()); + } + if (success_time.has_value()) { + preference_manager_.SetDictionaryInt64Value( + pref_name, SchedulerFields::kLastSuccessTimeKeyName, + success_time.value()); + } + if (failed_count.has_value()) { + preference_manager_.SetDictionaryInt64Value( + pref_name, SchedulerFields::kNumConsecutiveFailuresKeyName, + failed_count.value()); + } + if (has_pending.has_value()) { + preference_manager_.SetDictionaryBooleanValue( + pref_name, SchedulerFields::kHasPendingImmediateRequestKeyName, + has_pending.value()); + } + if (is_waiting.has_value()) { + preference_manager_.SetDictionaryBooleanValue( + pref_name, SchedulerFields::kIsWaitingForResultKeyName, + is_waiting.value()); + } + } + + PreferenceManager& preference_manager() { return preference_manager_; } + + private: + nearby::FakePreferenceManager preference_manager_; +}; + +TEST_F(NearbyShareSchedulerUtilsTest, ConvertToReadableScheduleSucceeds) { + absl::string_view test_pref = "test_pref"; + preference_manager().Remove(test_pref); + CreateSchedule(test_pref, /*attempt_time=*/123456L, /*success_time=*/345678L, + /*failed_count=*/123, /*has_pending=*/true, + /*is_waiting=*/false); + + std::string debug_str = + ConvertToReadableSchedule(preference_manager(), test_pref); + + EXPECT_THAT(debug_str, Eq("{attempt_time:1969-12-31 16:00:00, " + "success_time:1969-12-31 16:00:00, " + "failed_count:123, has_pending_request:true, " + "is_waiting_for_result:false}")); +} + +TEST_F(NearbyShareSchedulerUtilsTest, ConvertToReadableScheduleEmpty) { + absl::string_view test_pref = "test_pref"; + preference_manager().Remove(test_pref); + + std::string debug_str = + ConvertToReadableSchedule(preference_manager(), test_pref); + + EXPECT_THAT(debug_str, Eq("{}")); +} + +TEST_F(NearbyShareSchedulerUtilsTest, ConvertToReadableScheduleMissingFields) { + absl::string_view test_pref = "test_pref"; + preference_manager().Remove(test_pref); + CreateSchedule(test_pref, /*attempt_time=*/std::nullopt, + /*success_time=*/std::nullopt, + /*failed_count=*/345, /*has_pending=*/std::nullopt, + /*is_waiting=*/true); + + std::string debug_str = + ConvertToReadableSchedule(preference_manager(), test_pref); + + EXPECT_THAT(debug_str, Eq("{failed_count:345, is_waiting_for_result:true}")); +} + +} // namespace nearby::sharing