Skip to content

Inject DB connection info for E2E tests #390

@josecelano

Description

@josecelano

Parent: #384

Some E2E tests need to connect to the database directly. For example:

  • To grant the admin role to a normal user.
  • To get the user's tracker key.

There are two different test environments for E2E tests:

  • Shared: all tests share the same live env.
  • Isolated

For the shared test environment we need to know how to connect to the database because the test runner has not launched the env and it does not have the connection info.

For the time being, we are getting the configuration from the application (Index) configuration, but the configuration could not be the right one. For example, if we are running the test even with docker,which is the case, the database connection info is different depending on whether you are connecting from outside or inside the container.

What we are doing is manipulating the connection info in the configuration and maps it to the version used inside docker. I think it would be better to inject it with an env var.

We are already using env vars when we run the tests

TORRUST_INDEX_E2E_SHARED=true TORRUST_INDEX_E2E_PATH_CONFIG="./share/default/config/index.container.mysql.toml" cargo test

We could add a new one:

# MySQL
TORRUST_INDEX_E2E_SHARED=true TORRUST_INDEX_E2E_PATH_CONFIG="./share/default/config/index.container.mysql.toml" TORRUST_INDEX_E2E_DB_CONNECTION_URL="mysql://root:root_secret_password@localhost:3306/torrust_index_e2e_testing" cargo test

# SQLite
TORRUST_INDEX_E2E_SHARED=true TORRUST_INDEX_E2E_PATH_CONFIG="./share/default/config/index.container.sqlite3.toml" TORRUST_INDEX_E2E_DB_CONNECTION_URL="sqlite://./storage/index/lib/database/sqlite3.db?mode=rwc" cargo test

The following is the code that maps the internal docker DB connection info to the external version. E2E tests are executed and connect to the DB from outside the container.

    /// Provides a database connect URL to connect to the database. For example:
    ///
    /// `sqlite://storage/database/torrust_index_e2e_testing.db?mode=rwc`.
    ///
    /// It's used to run SQL queries against the database needed for some tests.
    pub fn database_connect_url(&self) -> Option<String> {
        let internal_connect_url = self
            .starting_settings
            .as_ref()
            .map(|settings| settings.database.connect_url.clone());

        match self.state() {
            State::RunningShared => {
                if let Some(db_path) = internal_connect_url {
                    let maybe_db_driver = database::get_driver(&db_path);

                    return match maybe_db_driver {
                        Ok(db_driver) => match db_driver {
                            database::Driver::Sqlite3 => Some(Self::overwrite_sqlite_path(&db_path, "./storage/index/lib")),
                            database::Driver::Mysql => Some(Self::overwrite_mysql_host(&db_path, "localhost")),
                        },
                        Err(_) => None,
                    };
                }
                None
            }
            State::RunningIsolated => internal_connect_url,
            State::Stopped => None,
        }
    }

    /// It overrides the `SQLite` file path in a `SQLx` database connection URL.
    /// For example:
    ///
    /// For:
    ///
    /// `sqlite:///var/lib/torrust/index/database/sqlite3.db?mode=rwc`.
    ///
    /// It changes the `mysql` host name to `localhost`:
    ///
    /// `sqlite://./storage/index/lib/database/sqlite3.db?mode=rwc`.
    ///
    /// For E2E tests, we use docker compose. Inside the container, the
    /// `SQLite` file path is not the same as the host path.
    fn overwrite_sqlite_path(db_path: &str, host_path: &str) -> String {
        // todo: inject value with env var
        db_path.replace("/var/lib/torrust/index", host_path)
    }

    /// It overrides the "Host" in a `SQLx` database connection URL.
    /// For example:
    ///
    /// For:
    ///
    /// `mysql://root:root_secret_password@mysql:3306/torrust_index_e2e_testing`.
    ///
    /// It changes the `mysql` host name to `localhost`:
    ///
    /// `mysql://root:root_secret_password@localhost:3306/torrust_index_e2e_testing`.
    ///
    /// For E2E tests, we use docker compose, internally the index connects to
    /// the `MySQL` database using the "mysql" host, which is the docker compose
    /// service name, but tests connects directly to the localhost since the
    /// `MySQL` is exposed to the host.
    fn overwrite_mysql_host(db_path: &str, new_host: &str) -> String {
        // todo: inject value with env var
        db_path.replace("@mysql:", &format!("@{new_host}:"))
    }

cc @da2ce7 @mario-nt

Metadata

Metadata

Assignees

Type

No type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions