Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DPE-2777] Basic sharding int test #279

Merged
merged 6 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
MiaAltieri marked this conversation as resolved.
Show resolved Hide resolved
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