Bug: Implement `BusinessProfileInterface` for `MockDb`



Spin off of #172 

Implement the missing implementation of MockDb for business profiles.
https://github.com/juspay/hyperswitch/blob/b8501f6ae6c0af0804d7f1e7cf9f50ebd303bf94/crates/router/src/db/business_profile.rs#L114

diff --git a/crates/diesel_models/src/business_profile.rs b/crates/diesel_models/src/business_profile.rs
index 74c75a2bf56..23fe0aed33f 100644
--- a/crates/diesel_models/src/business_profile.rs
+++ b/crates/diesel_models/src/business_profile.rs
@@ -70,3 +70,51 @@ pub struct BusinessProfileUpdateInternal {
     pub payout_routing_algorithm: Option<serde_json::Value>,
     pub is_recon_enabled: Option<bool>,
 }
+
+impl From<BusinessProfileNew> for BusinessProfile {
+    fn from(new: BusinessProfileNew) -> Self {
+        Self {
+            profile_id: new.profile_id,
+            merchant_id: new.merchant_id,
+            profile_name: new.profile_name,
+            created_at: new.created_at,
+            modified_at: new.modified_at,
+            return_url: new.return_url,
+            enable_payment_response_hash: new.enable_payment_response_hash,
+            payment_response_hash_key: new.payment_response_hash_key,
+            redirect_to_merchant_with_http_post: new.redirect_to_merchant_with_http_post,
+            webhook_details: new.webhook_details,
+            metadata: new.metadata,
+            routing_algorithm: new.routing_algorithm,
+            intent_fulfillment_time: new.intent_fulfillment_time,
+            frm_routing_algorithm: new.frm_routing_algorithm,
+            payout_routing_algorithm: new.payout_routing_algorithm,
+            is_recon_enabled: new.is_recon_enabled,
+        }
+    }
+}
+
+impl BusinessProfileUpdateInternal {
+    pub fn apply_changeset(self, source: BusinessProfile) -> BusinessProfile {
+        BusinessProfile {
+            profile_name: self.profile_name.unwrap_or(source.profile_name),
+            modified_at: self.modified_at.unwrap_or(source.modified_at),
+            return_url: self.return_url,
+            enable_payment_response_hash: self
+                .enable_payment_response_hash
+                .unwrap_or(source.enable_payment_response_hash),
+            payment_response_hash_key: self.payment_response_hash_key,
+            redirect_to_merchant_with_http_post: self
+                .redirect_to_merchant_with_http_post
+                .unwrap_or(source.redirect_to_merchant_with_http_post),
+            webhook_details: self.webhook_details,
+            metadata: self.metadata,
+            routing_algorithm: self.routing_algorithm,
+            intent_fulfillment_time: self.intent_fulfillment_time,
+            frm_routing_algorithm: self.frm_routing_algorithm,
+            payout_routing_algorithm: self.payout_routing_algorithm,
+            is_recon_enabled: self.is_recon_enabled.unwrap_or(source.is_recon_enabled),
+            ..source
+        }
+    }
+}
diff --git a/crates/router/src/db/business_profile.rs b/crates/router/src/db/business_profile.rs
index 72b1d16edcc..dff3bac792e 100644
--- a/crates/router/src/db/business_profile.rs
+++ b/crates/router/src/db/business_profile.rs
@@ -114,38 +114,90 @@ impl BusinessProfileInterface for Store {
 impl BusinessProfileInterface for MockDb {
     async fn insert_business_profile(
         &self,
-        _business_profile: business_profile::BusinessProfileNew,
+        business_profile: business_profile::BusinessProfileNew,
     ) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
-        Err(errors::StorageError::MockDbError)?
+        let business_profile_insert = business_profile::BusinessProfile::from(business_profile);
+        self.business_profiles
+            .lock()
+            .await
+            .push(business_profile_insert.clone());
+        Ok(business_profile_insert)
     }
 
     async fn find_business_profile_by_profile_id(
         &self,
-        _profile_id: &str,
+        profile_id: &str,
     ) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
-        Err(errors::StorageError::MockDbError)?
+        self.business_profiles
+            .lock()
+            .await
+            .iter()
+            .find(|business_profile| business_profile.profile_id == profile_id)
+            .ok_or(
+                errors::StorageError::ValueNotFound(format!(
+                    "No business profile found for profile_id = {}",
+                    profile_id
+                ))
+                .into(),
+            )
+            .cloned()
     }
 
     async fn update_business_profile_by_profile_id(
         &self,
-        _current_state: business_profile::BusinessProfile,
-        _business_profile_update: business_profile::BusinessProfileUpdateInternal,
+        current_state: business_profile::BusinessProfile,
+        business_profile_update: business_profile::BusinessProfileUpdateInternal,
     ) -> CustomResult<business_profile::BusinessProfile, errors::StorageError> {
-        Err(errors::StorageError::MockDbError)?
+        self.business_profiles
+            .lock()
+            .await
+            .iter_mut()
+            .find(|bp| bp.profile_id == current_state.profile_id)
+            .map(|bp| {
+                let business_profile_updated =
+                    business_profile_update.apply_changeset(current_state.clone());
+                *bp = business_profile_updated.clone();
+                business_profile_updated
+            })
+            .ok_or(
+                errors::StorageError::ValueNotFound(format!(
+                    "No business profile found for profile_id = {}",
+                    current_state.profile_id
+                ))
+                .into(),
+            )
     }
 
     async fn delete_business_profile_by_profile_id_merchant_id(
         &self,
-        _profile_id: &str,
-        _merchant_id: &str,
+        profile_id: &str,
+        merchant_id: &str,
     ) -> CustomResult<bool, errors::StorageError> {
-        Err(errors::StorageError::MockDbError)?
+        let mut business_profiles = self.business_profiles.lock().await;
+        let index = business_profiles
+            .iter()
+            .position(|bp| bp.profile_id == profile_id && bp.merchant_id == merchant_id)
+            .ok_or::<errors::StorageError>(errors::StorageError::ValueNotFound(format!(
+                "No business profile found for profile_id = {} and merchant_id = {}",
+                profile_id, merchant_id
+            )))?;
+        business_profiles.remove(index);
+        Ok(true)
     }
 
     async fn list_business_profile_by_merchant_id(
         &self,
-        _merchant_id: &str,
+        merchant_id: &str,
     ) -> CustomResult<Vec<business_profile::BusinessProfile>, errors::StorageError> {
-        Err(errors::StorageError::MockDbError)?
+        let business_profile_by_merchant_id = self
+            .business_profiles
+            .lock()
+            .await
+            .iter()
+            .filter(|business_profile| business_profile.merchant_id == merchant_id)
+            .cloned()
+            .collect();
+
+        Ok(business_profile_by_merchant_id)
     }
 }
diff --git a/crates/storage_impl/src/lib.rs b/crates/storage_impl/src/lib.rs
index 39ea480a789..5ff4d000b85 100644
--- a/crates/storage_impl/src/lib.rs
+++ b/crates/storage_impl/src/lib.rs
@@ -237,6 +237,7 @@ pub struct MockDb {
     pub mandates: Arc<Mutex<Vec<store::Mandate>>>,
     pub captures: Arc<Mutex<Vec<crate::store::capture::Capture>>>,
     pub merchant_key_store: Arc<Mutex<Vec<crate::store::merchant_key_store::MerchantKeyStore>>>,
+    pub business_profiles: Arc<Mutex<Vec<crate::store::business_profile::BusinessProfile>>>,
 }
 
 impl MockDb {
@@ -263,6 +264,7 @@ impl MockDb {
             mandates: Default::default(),
             captures: Default::default(),
             merchant_key_store: Default::default(),
+            business_profiles: Default::default(),
         }
     }
 }

Implement the missing implementation of MockDb for business profiles.

Closes #2039

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [x] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->


### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
