Skip to content

Commit

Permalink
[DPE-2777] Basic sharding int test (#279)
Browse files Browse the repository at this point in the history
## Issue
No integration tests for sainity check

## Solution
Add a sainty check test. i.e. deploy cluster, write data to mongos, read
data from shards
  • Loading branch information
MiaAltieri authored Oct 24, 2023
1 parent 1c272a5 commit 6f06a48
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 84 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ jobs:
- tls-integration
- backup-integration
- metric-integration
- sharding-integration
name: ${{ matrix.tox-environments }}
needs:
- lint
Expand Down
45 changes: 45 additions & 0 deletions tests/integration/sharding_tests/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.
from urllib.parse import quote_plus

from pymongo import MongoClient
from pytest_operator.plugin import OpsTest

from ..helpers import get_password

MONGOS_PORT = 27018
MONGOD_PORT = 27017


async def generate_mongodb_client(ops_test: OpsTest, app_name: str, mongos: bool):
"""Returns a MongoDB client for mongos/mongod."""
hosts = [unit.public_address for unit in ops_test.model.applications[app_name].units]
password = await get_password(ops_test, app_name)
port = MONGOS_PORT if mongos else MONGOD_PORT
hosts = [f"{host}:{port}" for host in hosts]
hosts = ",".join(hosts)
auth_source = ""
database = "admin"

return MongoClient(
f"mongodb://operator:"
f"{quote_plus(password)}@"
f"{hosts}/{quote_plus(database)}?"
f"{auth_source}"
)


def write_data_to_mongodb(client, db_name, coll_name, content) -> None:
"""Writes data to the provided collection and database."""
db = client[db_name]
horses_collection = db[coll_name]
horses_collection.insert_one(content)


def verify_data_mongodb(client, db_name, coll_name, key, value) -> bool:
"""Checks a key/value pair for a provided collection and database."""
db = client[db_name]
test_collection = db[coll_name]
query = test_collection.find({}, {key: 1})
return query[0][key] == value
120 changes: 120 additions & 0 deletions tests/integration/sharding_tests/test_sharding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
# Copyright 2023 Canonical Ltd.
# See LICENSE file for licensing details.
import pytest
from pytest_operator.plugin import OpsTest

from .helpers import generate_mongodb_client, verify_data_mongodb, write_data_to_mongodb

SHARD_ONE_APP_NAME = "shard-one"
SHARD_TWO_APP_NAME = "shard-two"
CONFIG_SERVER_APP_NAME = "config-server-one"
SHARD_REL_NAME = "sharding"
CONFIG_SERVER_REL_NAME = "config-server"
MONGODB_KEYFILE_PATH = "/var/snap/charmed-mongodb/current/etc/mongod/keyFile"
TIMEOUT = 15 * 60


@pytest.mark.abort_on_fail
async def test_build_and_deploy(ops_test: OpsTest) -> None:
"""Build and deploy a sharded cluster."""
my_charm = await ops_test.build_charm(".")
await ops_test.model.deploy(
my_charm,
num_units=2,
config={"role": "config-server"},
application_name=CONFIG_SERVER_APP_NAME,
)
await ops_test.model.deploy(
my_charm, num_units=2, config={"role": "shard"}, application_name=SHARD_ONE_APP_NAME
)
await ops_test.model.deploy(
my_charm, num_units=2, config={"role": "shard"}, application_name=SHARD_TWO_APP_NAME
)

async with ops_test.fast_forward():
await ops_test.model.wait_for_idle(
apps=[CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME, SHARD_TWO_APP_NAME],
idle_period=20,
raise_on_blocked=False,
timeout=TIMEOUT,
)

# TODO Future PR: assert that CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME, SHARD_TWO_APP_NAME
# are blocked waiting for relaitons


@pytest.mark.abort_on_fail
async def test_cluster_active(ops_test: OpsTest) -> None:
"""Tests the integration of cluster components works without error."""
await ops_test.model.integrate(
f"{SHARD_ONE_APP_NAME}:{SHARD_REL_NAME}",
f"{CONFIG_SERVER_APP_NAME}:{CONFIG_SERVER_REL_NAME}",
)
await ops_test.model.integrate(
f"{SHARD_TWO_APP_NAME}:{SHARD_REL_NAME}",
f"{CONFIG_SERVER_APP_NAME}:{CONFIG_SERVER_REL_NAME}",
)

async with ops_test.fast_forward():
await ops_test.model.wait_for_idle(
apps=[CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME, SHARD_TWO_APP_NAME],
idle_period=20,
status="active",
timeout=TIMEOUT,
)

# TODO Future PR: assert that CONFIG_SERVER_APP_NAME, SHARD_ONE_APP_NAME, SHARD_TWO_APP_NAME
# have the correct active statuses.


async def test_sharding(ops_test: OpsTest) -> None:
"""Tests writing data to mongos gets propagated to shards."""
# write data to mongos on both shards.
mongos_client = await generate_mongodb_client(
ops_test, app_name=CONFIG_SERVER_APP_NAME, mongos=True
)

# write data to shard one
write_data_to_mongodb(
mongos_client,
db_name="animals_database_1",
coll_name="horses",
content={"horse-breed": "unicorn", "real": True},
)
mongos_client.admin.command("movePrimary", "animals_database_1", to=SHARD_ONE_APP_NAME)

# write data to shard two
write_data_to_mongodb(
mongos_client,
db_name="animals_database_2",
coll_name="horses",
content={"horse-breed": "pegasus", "real": True},
)
mongos_client.admin.command("movePrimary", "animals_database_2", to=SHARD_TWO_APP_NAME)

# log into shard 1 verify data
shard_one_client = await generate_mongodb_client(
ops_test, app_name=SHARD_ONE_APP_NAME, mongos=False
)
has_correct_data = verify_data_mongodb(
shard_one_client,
db_name="animals_database_1",
coll_name="horses",
key="horse-breed",
value="unicorn",
)
assert has_correct_data, "data not written to shard-one"

# log into shard 2 verify data
shard_two_client = await generate_mongodb_client(
ops_test, app_name=SHARD_TWO_APP_NAME, mongos=False
)
has_correct_data = verify_data_mongodb(
shard_two_client,
db_name="animals_database_2",
coll_name="horses",
key="horse-breed",
value="pegasus",
)
assert has_correct_data, "data not written to shard-two"
84 changes: 0 additions & 84 deletions tests/integration/sharding_tests/test_sharding_components.py

This file was deleted.

15 changes: 15 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ deps =
commands =
pytest -v --tb native --log-cli-level=INFO -s --durations=0 {posargs} {[vars]tests_path}/integration/metrics_tests/test_metrics.py

[testenv:sharding-integration]
description = Run sharding integration tests
pass_env =
{[testenv]pass_env}
CI
CI_PACKED_CHARMS
deps =
pytest
juju==3.2.0.1
pytest-mock
pytest-operator
-r {tox_root}/requirements.txt
commands =
pytest -v --tb native --log-cli-level=INFO -s --durations=0 {posargs} {[vars]tests_path}/integration/sharding_tests/test_sharding.py


[testenv:integration]
description = Run all integration tests
Expand Down

0 comments on commit 6f06a48

Please sign in to comment.