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



Spin out from #172. Please refer to that issue for more information.
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index 0694b5a3020..0bc43e6d567 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -98,6 +98,7 @@ impl StorageInterface for Store {}
 #[derive(Clone)]
 pub struct MockDb {
     addresses: Arc<Mutex<Vec<storage::Address>>>,
+    configs: Arc<Mutex<Vec<storage::Config>>>,
     merchant_accounts: Arc<Mutex<Vec<storage::MerchantAccount>>>,
     merchant_connector_accounts: Arc<Mutex<Vec<storage::MerchantConnectorAccount>>>,
     payment_attempts: Arc<Mutex<Vec<storage::PaymentAttempt>>>,
@@ -121,6 +122,7 @@ impl MockDb {
     pub async fn new(redis: &crate::configs::settings::Settings) -> Self {
         Self {
             addresses: Default::default(),
+            configs: Default::default(),
             merchant_accounts: Default::default(),
             merchant_connector_accounts: Default::default(),
             payment_attempts: Default::default(),
diff --git a/crates/router/src/db/configs.rs b/crates/router/src/db/configs.rs
index b1697773706..95d249355da 100644
--- a/crates/router/src/db/configs.rs
+++ b/crates/router/src/db/configs.rs
@@ -1,4 +1,5 @@
 use error_stack::IntoReport;
+use storage_models::configs::ConfigUpdateInternal;
 
 use super::{cache, MockDb, Store};
 use crate::{
@@ -113,47 +114,107 @@ impl ConfigInterface for Store {
 impl ConfigInterface for MockDb {
     async fn insert_config(
         &self,
-        _config: storage::ConfigNew,
+        config: storage::ConfigNew,
     ) -> CustomResult<storage::Config, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let mut configs = self.configs.lock().await;
+
+        let config_new = storage::Config {
+            #[allow(clippy::as_conversions)]
+            id: configs.len() as i32,
+            key: config.key,
+            config: config.config,
+        };
+        configs.push(config_new.clone());
+        Ok(config_new)
     }
 
     async fn find_config_by_key(
         &self,
-        _key: &str,
+        key: &str,
     ) -> CustomResult<storage::Config, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let configs = self.configs.lock().await;
+        let config = configs.iter().find(|c| c.key == key).cloned();
+
+        config.ok_or_else(|| {
+            errors::StorageError::ValueNotFound("cannot find config".to_string()).into()
+        })
     }
 
     async fn update_config_by_key(
         &self,
-        _key: &str,
-        _config_update: storage::ConfigUpdate,
+        key: &str,
+        config_update: storage::ConfigUpdate,
     ) -> CustomResult<storage::Config, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let result = self
+            .configs
+            .lock()
+            .await
+            .iter_mut()
+            .find(|c| c.key == key)
+            .ok_or_else(|| {
+                errors::StorageError::ValueNotFound("cannot find config to update".to_string())
+                    .into()
+            })
+            .map(|c| {
+                let config_updated =
+                    ConfigUpdateInternal::from(config_update).create_config(c.clone());
+                *c = config_updated.clone();
+                config_updated
+            });
+
+        result
     }
     async fn update_config_cached(
         &self,
-        _key: &str,
-        _config_update: storage::ConfigUpdate,
+        key: &str,
+        config_update: storage::ConfigUpdate,
     ) -> CustomResult<storage::Config, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let result = self
+            .configs
+            .lock()
+            .await
+            .iter_mut()
+            .find(|c| c.key == key)
+            .ok_or_else(|| {
+                errors::StorageError::ValueNotFound("cannot find config to update".to_string())
+                    .into()
+            })
+            .map(|c| {
+                let config_updated =
+                    ConfigUpdateInternal::from(config_update).create_config(c.clone());
+                *c = config_updated.clone();
+                config_updated
+            });
+
+        result
     }
 
-    async fn delete_config_by_key(&self, _key: &str) -> CustomResult<bool, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+    async fn delete_config_by_key(&self, key: &str) -> CustomResult<bool, errors::StorageError> {
+        let mut configs = self.configs.lock().await;
+        let result = configs
+            .iter()
+            .position(|c| c.key == key)
+            .map(|index| {
+                configs.remove(index);
+                true
+            })
+            .ok_or_else(|| {
+                errors::StorageError::ValueNotFound("cannot find config to delete".to_string())
+                    .into()
+            });
+
+        result
     }
 
     async fn find_config_by_key_cached(
         &self,
-        _key: &str,
+        key: &str,
     ) -> CustomResult<storage::Config, errors::StorageError> {
-        // [#172]: Implement function for `MockDb`
-        Err(errors::StorageError::MockDbError)?
+        let configs = self.configs.lock().await;
+        let config = configs.iter().find(|c| c.key == key).cloned();
+
+        config.ok_or_else(|| {
+            errors::StorageError::ValueNotFound("cannot find config".to_string()).into()
+        })
     }
 }
diff --git a/crates/storage_models/src/configs.rs b/crates/storage_models/src/configs.rs
index f5988662642..81322ebac32 100644
--- a/crates/storage_models/src/configs.rs
+++ b/crates/storage_models/src/configs.rs
@@ -34,6 +34,12 @@ pub struct ConfigUpdateInternal {
     config: Option<String>,
 }
 
+impl ConfigUpdateInternal {
+    pub fn create_config(self, source: Config) -> Config {
+        Config { ..source }
+    }
+}
+
 impl From<ConfigUpdate> for ConfigUpdateInternal {
     fn from(config_update: ConfigUpdate) -> Self {
         match config_update {

## 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 its an obvious bug or documentation fix
that will have little conversation).
-->
The main motivation is to have MockDb stubs, help to void mocking, and invocation of external database api's.
For more information check https://github.com/juspay/hyperswitch/issues/172

Fixes https://github.com/juspay/hyperswitch/issues/997.


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