[fp-rs] Split fetcher.rs into directory module, added mock.

This commit is contained in:
Lucas Silva Shepard
2023-08-15 16:44:46 -07:00
parent b1fa76f560
commit 169c04c430
5 changed files with 138 additions and 43 deletions
+2 -2
View File
@@ -16,7 +16,7 @@ use bluetooth::{BleAddress, BleAdvertisement, ServiceData};
use crate::{
decoder::FpDecoder,
fetcher::{FpFetcher, FpFetcherLocal},
fetcher::{DeviceInfo, FpFetcher, FpFetcherFs},
};
/// Represents a FP device model ID.
@@ -78,7 +78,7 @@ impl FpPairingAdvertisement {
let model_id = format!("{}", u32::from_be_bytes(model_id.try_into().unwrap()));
// Retrieve device info of the device corresponding to this model ID.
let fetcher = FpFetcherLocal::new(String::from("./local"));
let fetcher = FpFetcherFs::new(String::from("./local"));
let device_info = fetcher
.get_device_info_from_model_id(&model_id)
.expect("Failed to create device info from model ID.");
@@ -11,27 +11,11 @@
// 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.
use std::fs;
use serde::Deserialize;
use crate::advertisement::ModelId;
/// Holds Fast Pair device information parsed from JSON.
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DeviceInfo {
image_url: String,
name: String,
}
/// Holds top-level Fast Pair information parsed from JSON. See `local`
/// directory for format.
#[derive(Deserialize)]
struct JsonData {
device: DeviceInfo,
}
/// Types that can fetch Fast Pair data from external storage (e.g. filesystem,
/// remote server).
pub(crate) trait FpFetcher {
@@ -41,36 +25,26 @@ pub(crate) trait FpFetcher {
) -> Result<DeviceInfo, anyhow::Error>;
}
/// A unit struct for retrieving Fast Pair information from the local filesystem.
pub(crate) struct FpFetcherLocal {
path: String,
/// Holds Fast Pair device information parsed from JSON.
#[derive(Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct DeviceInfo {
image_url: String,
name: String,
}
impl FpFetcherLocal {
pub(crate) fn new(path: String) -> Self {
FpFetcherLocal { path }
}
}
impl FpFetcher for FpFetcherLocal {
/// Retrieve device information for the provided Model ID. Currently,
/// this information is saved locally. In the future, this should instead
/// be retrieved from a remote server and cached.
/// b/294456411
fn get_device_info_from_model_id(
&self,
model_id: &ModelId,
) -> Result<DeviceInfo, anyhow::Error> {
let file_path = format!("{}/{}.json", self.path, model_id);
let contents = fs::read_to_string(file_path).expect("Couldn't find or open file.");
let model_info: JsonData = serde_json::from_str(&contents)?;
Ok(model_info.device)
}
/// Holds top-level Fast Pair information parsed from JSON. See `local`
/// directory for format.
#[derive(Deserialize)]
pub(super) struct JsonData {
device: DeviceInfo,
}
impl DeviceInfo {
pub(crate) fn new(image_url: String, name: String) -> Self {
DeviceInfo { image_url, name }
}
pub(crate) fn name(&self) -> &String {
&self.name
}
@@ -79,3 +53,10 @@ impl DeviceInfo {
&self.image_url
}
}
impl JsonData {
// Returns the `DeviceInfo` associated with parsed self, consuming self.
pub(super) fn device(self) -> DeviceInfo {
self.device
}
}
+49
View File
@@ -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.
use std::fs;
use crate::{
advertisement::ModelId,
fetcher::{DeviceInfo, FpFetcher, JsonData},
};
/// A struct for retrieving Fast Pair information from the local filesystem.
pub(crate) struct FpFetcherFs {
path: String,
}
impl FpFetcherFs {
pub(crate) fn new(path: String) -> Self {
FpFetcherFs { path }
}
}
impl FpFetcher for FpFetcherFs {
/// Retrieve device information for the provided Model ID. Currently,
/// this information is saved locally. In the future, this should instead
/// be retrieved from a remote server and cached.
/// b/294456411
fn get_device_info_from_model_id(
&self,
model_id: &ModelId,
) -> Result<DeviceInfo, anyhow::Error> {
let file_path = format!("{}/{}.json", self.path, model_id);
let contents = fs::read_to_string(file_path).expect("Couldn't find or open file.");
let model_info: JsonData = serde_json::from_str(&contents)?;
Ok(model_info.device())
}
}
@@ -0,0 +1,43 @@
// 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.
use crate::{
advertisement::ModelId,
fetcher::{DeviceInfo, FpFetcher},
};
/// A struct for mocking retrieval of Fast Pair data.
pub(crate) struct FpFetcherMock {
get_device_info_from_model_id: Result<DeviceInfo, anyhow::Error>,
}
impl FpFetcherMock {
pub(crate) fn new(get_device_info_from_model_id: Result<DeviceInfo, anyhow::Error>) -> Self {
FpFetcherMock {
get_device_info_from_model_id,
}
}
}
impl FpFetcher for FpFetcherMock {
fn get_device_info_from_model_id(
&self,
_model_id: &ModelId,
) -> Result<DeviceInfo, anyhow::Error> {
match &self.get_device_info_from_model_id {
Ok(result) => Ok(result.clone()),
Err(_) => Err(anyhow::anyhow!("intentional mock error")),
}
}
}
@@ -0,0 +1,22 @@
// 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.
pub(crate) mod common;
pub(crate) mod fs;
#[cfg(test)]
pub(crate) mod mock;
pub(crate) use common::*;
pub(crate) use fs::*;