Bug: [FEATURE] Implement `MerchantKeyStoreInterface` for `MockDb`



### Feature Description

Currently the MerchantKeyStoreInterface is not implemented for MockDb. It is required for merchant account functions. And without this implementation, we cannot write tests for them.

### Possible Implementation

Checkout #172 for more details.

### Have you spent some time to check if this feature request has been raised before?

- [X] I checked and didn't find similar issue

### Have you read the Contributing Guidelines?

- [X] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

None
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index 304e2a0fc74..caf6264db61 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -120,6 +120,7 @@ pub struct MockDb {
     disputes: Arc<Mutex<Vec<storage::Dispute>>>,
     lockers: Arc<Mutex<Vec<storage::LockerMockUp>>>,
     mandates: Arc<Mutex<Vec<storage::Mandate>>>,
+    merchant_key_store: Arc<Mutex<Vec<storage::MerchantKeyStore>>>,
 }
 
 impl MockDb {
@@ -144,6 +145,7 @@ impl MockDb {
             disputes: Default::default(),
             lockers: Default::default(),
             mandates: Default::default(),
+            merchant_key_store: Default::default(),
         }
     }
 }
diff --git a/crates/router/src/db/merchant_connector_account.rs b/crates/router/src/db/merchant_connector_account.rs
index 18358ae955d..d41b3a7c9ad 100644
--- a/crates/router/src/db/merchant_connector_account.rs
+++ b/crates/router/src/db/merchant_connector_account.rs
@@ -377,7 +377,7 @@ impl MerchantConnectorAccountInterface for MockDb {
             .await
             .iter()
             .find(|account| {
-                account.merchant_id == merchant_id && account.connector_name == connector
+                account.merchant_id == merchant_id && account.connector_label == connector
             })
             .cloned()
             .async_map(|account| async {
@@ -565,6 +565,8 @@ mod merchant_connector_account_cache_tests {
     use common_utils::date_time;
     use diesel_models::enums::ConnectorType;
     use error_stack::ResultExt;
+    use masking::PeekInterface;
+    use time::macros::datetime;
 
     use crate::{
         cache::{CacheKind, ACCOUNTS_CACHE},
@@ -573,7 +575,7 @@ mod merchant_connector_account_cache_tests {
             cache, merchant_connector_account::MerchantConnectorAccountInterface,
             merchant_key_store::MerchantKeyStoreInterface, MasterKeyInterface, MockDb,
         },
-        services::{PubSubInterface, RedisConnInterface},
+        services::{self, PubSubInterface, RedisConnInterface},
         types::{
             domain::{self, behaviour::Conversion, types as domain_types},
             storage,
@@ -582,12 +584,11 @@ mod merchant_connector_account_cache_tests {
 
     #[allow(clippy::unwrap_used)]
     #[tokio::test]
-    #[ignore = "blocked on MockDb implementation of merchant key store"]
     async fn test_connector_label_cache() {
         let db = MockDb::new(&Default::default()).await;
 
         let redis_conn = db.get_redis_conn();
-        let key = db.get_master_key();
+        let master_key = db.get_master_key();
         redis_conn
             .subscribe("hyperswitch_invalidate")
             .await
@@ -597,13 +598,34 @@ mod merchant_connector_account_cache_tests {
         let connector_label = "stripe_USA";
         let merchant_connector_id = "simple_merchant_connector_id";
 
+        db.insert_merchant_key_store(
+            domain::MerchantKeyStore {
+                merchant_id: merchant_id.into(),
+                key: domain_types::encrypt(
+                    services::generate_aes256_key().unwrap().to_vec().into(),
+                    master_key,
+                )
+                .await
+                .unwrap(),
+                created_at: datetime!(2023-02-01 0:00),
+            },
+            &master_key.to_vec().into(),
+        )
+        .await
+        .unwrap();
+
+        let merchant_key = db
+            .get_merchant_key_store_by_merchant_id(merchant_id, &master_key.to_vec().into())
+            .await
+            .unwrap();
+
         let mca = domain::MerchantConnectorAccount {
             id: Some(1),
             merchant_id: merchant_id.to_string(),
             connector_name: "stripe".to_string(),
             connector_account_details: domain_types::encrypt(
                 serde_json::Value::default().into(),
-                key,
+                merchant_key.key.get_inner().peek(),
             )
             .await
             .unwrap(),
@@ -623,19 +645,14 @@ mod merchant_connector_account_cache_tests {
             connector_webhook_details: None,
         };
 
-        let key_store = db
-            .get_merchant_key_store_by_merchant_id(merchant_id, &key.to_vec().into())
-            .await
-            .unwrap();
-
-        db.insert_merchant_connector_account(mca, &key_store)
+        db.insert_merchant_connector_account(mca, &merchant_key)
             .await
             .unwrap();
         let find_call = || async {
             db.find_merchant_connector_account_by_merchant_id_connector_label(
                 merchant_id,
                 connector_label,
-                &key_store,
+                &merchant_key,
             )
             .await
             .unwrap()
diff --git a/crates/router/src/db/merchant_key_store.rs b/crates/router/src/db/merchant_key_store.rs
index 0dfbce05422..32bf9f4270b 100644
--- a/crates/router/src/db/merchant_key_store.rs
+++ b/crates/router/src/db/merchant_key_store.rs
@@ -49,6 +49,7 @@ impl MerchantKeyStoreInterface for Store {
             .await
             .change_context(errors::StorageError::DecryptionError)
     }
+
     async fn get_merchant_key_store_by_merchant_id(
         &self,
         merchant_id: &str,
@@ -95,18 +96,119 @@ impl MerchantKeyStoreInterface for Store {
 impl MerchantKeyStoreInterface for MockDb {
     async fn insert_merchant_key_store(
         &self,
-        _merchant_key_store: domain::MerchantKeyStore,
-        _key: &Secret<Vec<u8>>,
+        merchant_key_store: domain::MerchantKeyStore,
+        key: &Secret<Vec<u8>>,
     ) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError.into())
+        let mut locked_merchant_key_store = self.merchant_key_store.lock().await;
+
+        if locked_merchant_key_store
+            .iter()
+            .any(|merchant_key| merchant_key.merchant_id == merchant_key_store.merchant_id)
+        {
+            Err(errors::StorageError::DuplicateValue {
+                entity: "merchant_key_store",
+                key: Some(merchant_key_store.merchant_id.clone()),
+            })?;
+        }
+
+        let merchant_key = Conversion::convert(merchant_key_store)
+            .await
+            .change_context(errors::StorageError::MockDbError)?;
+        locked_merchant_key_store.push(merchant_key.clone());
+
+        merchant_key
+            .convert(key)
+            .await
+            .change_context(errors::StorageError::DecryptionError)
     }
+
     async fn get_merchant_key_store_by_merchant_id(
         &self,
-        _merchant_id: &str,
-        _key: &Secret<Vec<u8>>,
+        merchant_id: &str,
+        key: &Secret<Vec<u8>>,
     ) -> CustomResult<domain::MerchantKeyStore, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError.into())
+        self.merchant_key_store
+            .lock()
+            .await
+            .iter()
+            .find(|merchant_key| merchant_key.merchant_id == merchant_id)
+            .cloned()
+            .ok_or(errors::StorageError::ValueNotFound(String::from(
+                "merchant_key_store",
+            )))?
+            .convert(key)
+            .await
+            .change_context(errors::StorageError::DecryptionError)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use time::macros::datetime;
+
+    use crate::{
+        db::{merchant_key_store::MerchantKeyStoreInterface, MasterKeyInterface, MockDb},
+        services,
+        types::domain::{self, types as domain_types},
+    };
+
+    #[allow(clippy::unwrap_used)]
+    #[tokio::test]
+    async fn test_mock_db_merchant_key_store_interface() {
+        let mock_db = MockDb::new(&Default::default()).await;
+        let master_key = mock_db.get_master_key();
+        let merchant_id = "merchant1";
+
+        let merchant_key1 = mock_db
+            .insert_merchant_key_store(
+                domain::MerchantKeyStore {
+                    merchant_id: merchant_id.into(),
+                    key: domain_types::encrypt(
+                        services::generate_aes256_key().unwrap().to_vec().into(),
+                        master_key,
+                    )
+                    .await
+                    .unwrap(),
+                    created_at: datetime!(2023-02-01 0:00),
+                },
+                &master_key.to_vec().into(),
+            )
+            .await
+            .unwrap();
+
+        let found_merchant_key1 = mock_db
+            .get_merchant_key_store_by_merchant_id(merchant_id, &master_key.to_vec().into())
+            .await
+            .unwrap();
+
+        assert_eq!(found_merchant_key1.merchant_id, merchant_key1.merchant_id);
+        assert_eq!(found_merchant_key1.key, merchant_key1.key);
+
+        let insert_duplicate_merchant_key1_result = mock_db
+            .insert_merchant_key_store(
+                domain::MerchantKeyStore {
+                    merchant_id: merchant_id.into(),
+                    key: domain_types::encrypt(
+                        services::generate_aes256_key().unwrap().to_vec().into(),
+                        master_key,
+                    )
+                    .await
+                    .unwrap(),
+                    created_at: datetime!(2023-02-01 0:00),
+                },
+                &master_key.to_vec().into(),
+            )
+            .await;
+        assert!(insert_duplicate_merchant_key1_result.is_err());
+
+        let find_non_existent_merchant_key_result = mock_db
+            .get_merchant_key_store_by_merchant_id("non_existent", &master_key.to_vec().into())
+            .await;
+        assert!(find_non_existent_merchant_key_result.is_err());
+
+        let find_merchant_key_with_incorrect_master_key_result = mock_db
+            .get_merchant_key_store_by_merchant_id(merchant_id, &vec![0; 32].into())
+            .await;
+        assert!(find_merchant_key_with_incorrect_master_key_result.is_err());
     }
 }
diff --git a/crates/router/src/types/storage.rs b/crates/router/src/types/storage.rs
index 396315b4c85..0b66ac7d8a0 100644
--- a/crates/router/src/types/storage.rs
+++ b/crates/router/src/types/storage.rs
@@ -9,28 +9,27 @@ pub mod enums;
 pub mod ephemeral_key;
 pub mod events;
 pub mod file;
+#[cfg(feature = "kv_store")]
+pub mod kv;
 pub mod locker_mock_up;
 pub mod mandate;
 pub mod merchant_account;
 pub mod merchant_connector_account;
+pub mod merchant_key_store;
 pub mod payment_attempt;
 pub mod payment_intent;
 pub mod payment_method;
 pub mod payout_attempt;
 pub mod payouts;
 pub mod process_tracker;
-pub mod reverse_lookup;
-
 mod query;
 pub mod refund;
-
-#[cfg(feature = "kv_store")]
-pub mod kv;
+pub mod reverse_lookup;
 
 pub use self::{
     address::*, api_keys::*, cards_info::*, configs::*, connector_response::*, customers::*,
     dispute::*, ephemeral_key::*, events::*, file::*, locker_mock_up::*, mandate::*,
-    merchant_account::*, merchant_connector_account::*, payment_attempt::*, payment_intent::*,
-    payment_method::*, payout_attempt::*, payouts::*, process_tracker::*, refund::*,
-    reverse_lookup::*,
+    merchant_account::*, merchant_connector_account::*, merchant_key_store::*, payment_attempt::*,
+    payment_intent::*, payment_method::*, payout_attempt::*, payouts::*, process_tracker::*,
+    refund::*, reverse_lookup::*,
 };
diff --git a/crates/router/src/types/storage/merchant_key_store.rs b/crates/router/src/types/storage/merchant_key_store.rs
new file mode 100644
index 00000000000..29371aed08f
--- /dev/null
+++ b/crates/router/src/types/storage/merchant_key_store.rs
@@ -0,0 +1 @@
+pub use diesel_models::merchant_key_store::MerchantKeyStore;

## 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 -->
This PR adds the `MockDb` implementation of `MerchantKeyStoreInterface`. In addition, this PR includes a fix for the `test_connector_label_cache` test in the `merchant_connector_account` module.

## 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 its an obvious bug or documentation fix
that will have little conversation).
-->
Fixes #1697.

## 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)?
-->
<img alt="cargo-nextest output" src="https://github.com/juspay/hyperswitch/assets/22217505/710b1e23-9bc2-4953-80a0-073f3ba8d606">

## 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 submitted code
- [x] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
