From ed9e03289001f052babba2be373e09ba02978ed0 Mon Sep 17 00:00:00 2001 From: Philip Wafula Date: Thu, 3 Jun 2021 13:40:51 +0000 Subject: [PATCH] Philip/management integration tests --- apps/cic-meta/scripts/server/handlers.ts | 4 +- .../cic_notify/tasks/sms/africastalking.py | 2 +- apps/cic-notify/setup.cfg | 1 + apps/cic-ussd/.config/test/integration.ini | 4 + apps/cic-ussd/cic_ussd/db/ussd_menu.json | 32 +- apps/cic-ussd/cic_ussd/metadata/base.py | 44 +- apps/cic-ussd/cic_ussd/metadata/signer.py | 3 +- apps/cic-ussd/cic_ussd/processor.py | 9 +- .../cic_ussd/state_machine/logic/pin.py | 17 +- .../cic_ussd/state_machine/logic/user.py | 63 +- apps/cic-ussd/cic_ussd/translation.py | 2 + apps/cic-ussd/requirements.txt | 6 +- .../states/account_management_states.json | 5 +- apps/cic-ussd/test_requirements.txt | 8 +- apps/cic-ussd/tests/conftest.py | 1 + apps/cic-ussd/tests/fixtures/integration.py | 249 +++ apps/cic-ussd/tests/helpers/accounts.py | 26 + .../tests/integration/ext/validator.py | 11 + apps/cic-ussd/tests/integration/run.sh | 2 + .../test_account_creation.tavern.yaml | 466 +++++ .../test_account_management.tavern.yaml | 587 ++++++ .../test_profile_management.tavern.yaml | 1573 +++++++++++++++++ .../integration/test_transactions.tavern.yaml | 282 +++ .../gender_setting_transitions.json | 12 +- .../location_setting_transitions.json | 12 +- .../transitions/name_setting_transitions.json | 41 +- .../transitions/pin_setting_transitions.json | 6 +- .../products_setting_transitions.json | 9 +- .../user_metadata_transitions.json | 2 +- apps/cic-ussd/var/lib/locale/ussd.en.yml | 35 +- apps/cic-ussd/var/lib/locale/ussd.sw.yml | 47 +- 31 files changed, 3437 insertions(+), 124 deletions(-) create mode 100644 apps/cic-ussd/.config/test/integration.ini create mode 100644 apps/cic-ussd/tests/fixtures/integration.py create mode 100644 apps/cic-ussd/tests/helpers/accounts.py create mode 100644 apps/cic-ussd/tests/integration/ext/validator.py create mode 100644 apps/cic-ussd/tests/integration/run.sh create mode 100644 apps/cic-ussd/tests/integration/test_account_creation.tavern.yaml create mode 100644 apps/cic-ussd/tests/integration/test_account_management.tavern.yaml create mode 100644 apps/cic-ussd/tests/integration/test_profile_management.tavern.yaml create mode 100644 apps/cic-ussd/tests/integration/test_transactions.tavern.yaml diff --git a/apps/cic-meta/scripts/server/handlers.ts b/apps/cic-meta/scripts/server/handlers.ts index 90dc622a..08bf2d9b 100644 --- a/apps/cic-meta/scripts/server/handlers.ts +++ b/apps/cic-meta/scripts/server/handlers.ts @@ -31,7 +31,7 @@ function handleNoMergeGet(db, digest, keystore) { doh(e); }); }).catch((e) => { - console.error('mesage', e); + console.error('message', e); doh(e); }); }) @@ -46,7 +46,7 @@ function handleServerMergePost(data, db, digest, keystore, signer) { let e = undefined; let s = undefined; if (v === undefined) { - s = new Syncable(digest, data); + s = new Syncable(digest, o); s.onwrap = (e) => { whohoo(e.toJSON()); }; diff --git a/apps/cic-notify/cic_notify/tasks/sms/africastalking.py b/apps/cic-notify/cic_notify/tasks/sms/africastalking.py index af48ac58..e52b030f 100644 --- a/apps/cic-notify/cic_notify/tasks/sms/africastalking.py +++ b/apps/cic-notify/cic_notify/tasks/sms/africastalking.py @@ -56,7 +56,7 @@ class AfricasTalkingNotifier: response = self.api_client.send(message=message, recipients=[recipient]) logg.debug(f'africastalking response no-sender-id {response}') - recipients = response.get('Recipients') + recipients = response.get('SMSMessageData').get('Recipients') if len(recipients) != 1: status = response.get('SMSMessageData').get('Message') diff --git a/apps/cic-notify/setup.cfg b/apps/cic-notify/setup.cfg index d4606598..ea3a2f05 100644 --- a/apps/cic-notify/setup.cfg +++ b/apps/cic-notify/setup.cfg @@ -28,6 +28,7 @@ packages = cic_notify cic_notify.db cic_notify.db.models + cic_notify.ext cic_notify.tasks.sms cic_notify.runnable scripts = diff --git a/apps/cic-ussd/.config/test/integration.ini b/apps/cic-ussd/.config/test/integration.ini new file mode 100644 index 00000000..4fc189e9 --- /dev/null +++ b/apps/cic-ussd/.config/test/integration.ini @@ -0,0 +1,4 @@ +[test] +gift_value = 50.00 +server_url = http://localhost:63315/ +token_symbol = GFT diff --git a/apps/cic-ussd/cic_ussd/db/ussd_menu.json b/apps/cic-ussd/cic_ussd/db/ussd_menu.json index 0f0d24eb..ecc98173 100644 --- a/apps/cic-ussd/cic_ussd/db/ussd_menu.json +++ b/apps/cic-ussd/cic_ussd/db/ussd_menu.json @@ -238,13 +238,43 @@ "description": "Menu to display a user's entire profile", "display_key": "ussd.kenya.display_user_metadata", "name": "display_user_metadata", - "parent": "account_management" + "parent": "metadata_management" }, "41": { "description": "The recipient is not in the system", "display_key": "ussd.kenya.exit_invalid_recipient", "name": "exit_invalid_recipient", "parent": null + }, + "42": { + "description": "Pin entry menu for changing name data.", + "display_key": "ussd.kenya.name_edit_pin_authorization", + "name": "name_edit_pin_authorization", + "parent": "metadata_management" + }, + "43": { + "description": "Pin entry menu for changing gender data.", + "display_key": "ussd.kenya.gender_edit_pin_authorization", + "name": "gender_edit_pin_authorization", + "parent": "metadata_management" + }, + "44": { + "description": "Pin entry menu for changing location data.", + "display_key": "ussd.kenya.location_edit_pin_authorization", + "name": "location_edit_pin_authorization", + "parent": "metadata_management" + }, + "45": { + "description": "Pin entry menu for changing products data.", + "display_key": "ussd.kenya.products_edit_pin_authorization", + "name": "products_edit_pin_authorization", + "parent": "metadata_management" + }, + "46": { + "description": "Pin confirmation for pin change.", + "display_key": "ussd.kenya.new_pin_confirmation", + "name": "new_pin_confirmation", + "parent": "metadata_management" } } diff --git a/apps/cic-ussd/cic_ussd/metadata/base.py b/apps/cic-ussd/cic_ussd/metadata/base.py index a60538de..b4cb3691 100644 --- a/apps/cic-ussd/cic_ussd/metadata/base.py +++ b/apps/cic-ussd/cic_ussd/metadata/base.py @@ -78,28 +78,27 @@ class MetadataRequestsHandler(Metadata): :param data: The data to be stored in the metadata server. :type data: dict|str """ - data = json.dumps(data).encode('utf-8') + data = json.dumps(data) result = make_request(method='POST', url=self.url, data=data, headers=self.headers) metadata_http_error_handler(result=result) - metadata = result.content + metadata = result.json() self.edit(data=metadata) - def edit(self, data: bytes): + def edit(self, data: Union[Dict, str]): """ This function is responsible for editing data in the metadata server corresponding to a unique pointer. :param data: The data to be edited in the metadata server. - :type data: bytes + :type data: dict """ cic_meta_signer = Signer() signature = cic_meta_signer.sign_digest(data=data) algorithm = cic_meta_signer.get_operational_key().get('algo') - decoded_data = data.decode('utf-8') formatted_data = { - 'm': data.decode('utf-8'), + 'm': json.dumps(data), 's': { 'engine': self.engine, 'algo': algorithm, 'data': signature, - 'digest': json.loads(data).get('digest'), + 'digest': data.get('digest'), } } formatted_data = json.dumps(formatted_data) @@ -110,19 +109,32 @@ class MetadataRequestsHandler(Metadata): decoded_identifier = self.identifier.decode("utf-8") except UnicodeDecodeError: decoded_identifier = self.identifier.hex() - logg.info(f'identifier: {decoded_identifier}. metadata pointer: {self.metadata_pointer} set to: {decoded_data}.') + logg.info(f'identifier: {decoded_identifier}. metadata pointer: {self.metadata_pointer} set to: {data}.') def query(self): - """This function is responsible for querying the metadata server for data corresponding to a unique pointer.""" + """ + :return: + :rtype: + """ + # retrieve the metadata result = make_request(method='GET', url=self.url) metadata_http_error_handler(result=result) - response_data = result.json() - data = json.loads(response_data) - if not isinstance(data, dict): - raise ValueError(f'Invalid data object: {data}.') + + # json serialize retrieved data + result_data = result.json() + + # validate result data format + if not isinstance(result_data, dict): + raise ValueError(f'Invalid result data object: {result_data}.') + if result.status_code == 200 and self.cic_type == ':cic.person': + # validate person metadata person = Person() - deserialized_person = person.deserialize(person_data=data) - data = json.dumps(deserialized_person.serialize()) - cache_data(self.metadata_pointer, data=data) + person_data = person.deserialize(person_data=result_data) + + # format new person data for caching + data = json.dumps(person_data.serialize()) + + # cache metadata + cache_data(key=self.metadata_pointer, data=data) logg.debug(f'caching: {data} with key: {self.metadata_pointer}') diff --git a/apps/cic-ussd/cic_ussd/metadata/signer.py b/apps/cic-ussd/cic_ussd/metadata/signer.py index dc187d29..39544a32 100644 --- a/apps/cic-ussd/cic_ussd/metadata/signer.py +++ b/apps/cic-ussd/cic_ussd/metadata/signer.py @@ -47,14 +47,13 @@ class Signer: logg.debug(f'using signing key: {key_id}, algorithm: {key_algorithm}') return gpg_keys[0] - def sign_digest(self, data: bytes): + def sign_digest(self, data: dict): """ :param data: :type data: :return: :rtype: """ - data = json.loads(data) digest = data['digest'] key_id = self.get_operational_key().get('keyid') signature = self.gpg.sign(digest, passphrase=self.gpg_passphrase, keyid=key_id) diff --git a/apps/cic-ussd/cic_ussd/processor.py b/apps/cic-ussd/cic_ussd/processor.py index 864cd53f..3958e748 100644 --- a/apps/cic-ussd/cic_ussd/processor.py +++ b/apps/cic-ussd/cic_ussd/processor.py @@ -251,9 +251,9 @@ def process_display_user_metadata(user: Account, display_key: str): identifier=blockchain_address_to_metadata_pointer(blockchain_address=user.blockchain_address), cic_type=':cic.person' ) - user_metadata = get_cached_data(key) - if user_metadata: - user_metadata = json.loads(user_metadata) + cached_metadata = get_cached_data(key) + if cached_metadata: + user_metadata = json.loads(cached_metadata) contact_data = get_contact_data_from_vcard(vcard=user_metadata.get('vcard')) logg.debug(f'{contact_data}') full_name = f'{contact_data.get("given")} {contact_data.get("family")}' @@ -433,7 +433,8 @@ def process_request(user_input: str, user: Account, ussd_session: Optional[dict] 'exit_invalid_pin', 'exit_invalid_new_pin', 'exit_pin_mismatch', - 'exit_invalid_request' + 'exit_invalid_request', + 'exit_successful_transaction' ] and person_metadata is not None: return UssdMenu.find_by_name(name='start') else: diff --git a/apps/cic-ussd/cic_ussd/state_machine/logic/pin.py b/apps/cic-ussd/cic_ussd/state_machine/logic/pin.py index 3577699d..5f51e602 100644 --- a/apps/cic-ussd/cic_ussd/state_machine/logic/pin.py +++ b/apps/cic-ussd/cic_ussd/state_machine/logic/pin.py @@ -13,7 +13,7 @@ import bcrypt # local imports from cic_ussd.db.models.account import AccountStatus, Account -from cic_ussd.encoder import PasswordEncoder, create_password_hash +from cic_ussd.encoder import PasswordEncoder, create_password_hash, check_password_hash from cic_ussd.operations import persist_session_to_db_task, create_or_update_session from cic_ussd.redis import InMemoryStore @@ -78,9 +78,13 @@ def save_initial_pin_to_session_data(state_machine_data: Tuple[str, dict, Accoun # set initial pin data initial_pin = create_password_hash(user_input) - session_data = { - 'initial_pin': initial_pin - } + if ussd_session.get('session_data'): + session_data = ussd_session.get('session_data') + session_data['initial_pin'] = initial_pin + else: + session_data = { + 'initial_pin': initial_pin + } # create new in memory ussd session with current ussd session data create_or_update_session( @@ -103,9 +107,8 @@ def pins_match(state_machine_data: Tuple[str, dict, Account]) -> bool: """ user_input, ussd_session, user = state_machine_data initial_pin = ussd_session.get('session_data').get('initial_pin') - fernet = PasswordEncoder(PasswordEncoder.key) - initial_pin = fernet.decrypt(initial_pin.encode()) - return bcrypt.checkpw(user_input.encode(), initial_pin) + logg.debug(f'USSD SESSION: {ussd_session}') + return check_password_hash(user_input, initial_pin) def complete_pin_change(state_machine_data: Tuple[str, dict, Account]): diff --git a/apps/cic-ussd/cic_ussd/state_machine/logic/user.py b/apps/cic-ussd/cic_ussd/state_machine/logic/user.py index da8a87db..d2db5d29 100644 --- a/apps/cic-ussd/cic_ussd/state_machine/logic/user.py +++ b/apps/cic-ussd/cic_ussd/state_machine/logic/user.py @@ -64,13 +64,17 @@ def process_gender_user_input(user: Account, user_input: str): if user.preferred_language == 'en': if user_input == '1': gender = 'Male' - else: + elif user_input == '2': gender = 'Female' + elif user_input == '3': + gender = 'Other' else: if user_input == '1': gender = 'Mwanaume' - else: + elif user_input == '2': gender = 'Mwanamke' + elif user_input == '3': + gender = 'Nyingine' return gender @@ -88,14 +92,18 @@ def save_metadata_attribute_to_session_data(state_machine_data: Tuple[str, dict, key = '' if 'given_name' in current_state: key = 'given_name' - elif 'family_name' in current_state: + + if 'family_name' in current_state: key = 'family_name' - elif 'gender' in current_state: + + if 'gender' in current_state: key = 'gender' user_input = process_gender_user_input(user=user, user_input=user_input) - elif 'location' in current_state: + + if 'location' in current_state: key = 'location' - elif 'products' in current_state: + + if 'products' in current_state: key = 'products' # check if there is existing session data @@ -121,12 +129,20 @@ def format_user_metadata(metadata: dict, user: Account): gender = metadata.get('gender') given_name = metadata.get('given_name') family_name = metadata.get('family_name') - location = { - "area_name": metadata.get('location') - } - products = [] - if metadata.get('products'): + + # check whether there's existing location data + if isinstance(metadata.get('location'), dict): + location = metadata.get('location') + else: + location = { + "area_name": metadata.get('location') + } + # check whether it is a list + if isinstance(metadata.get('products'), list): + products = metadata.get('products') + else: products = metadata.get('products').split(',') + phone_number = user.phone_number date_registered = int(user.created.replace().timestamp()) blockchain_address = user.blockchain_address @@ -192,28 +208,27 @@ def edit_user_metadata_attribute(state_machine_data: Tuple[str, dict, Account]): # validate user metadata person = Person() user_metadata = json.loads(user_metadata) - deserialized_person = person.deserialize(person_data=user_metadata) # edit specific metadata attribute if given_name: - deserialized_person.given_name = given_name - elif family_name: - deserialized_person.family_name = family_name - elif gender: - deserialized_person.gender = gender - elif location: + user_metadata['given_name'] = given_name + if family_name: + user_metadata['family_name'] = family_name + if gender: + user_metadata['gender'] = gender + if location: # get existing location metadata: location_data = user_metadata.get('location') location_data['area_name'] = location - deserialized_person.location = location_data - elif products: - deserialized_person.products = products + user_metadata['location'] = location_data + if products: + user_metadata['products'] = products - edited_metadata = deserialized_person.serialize() + user_metadata = format_user_metadata(metadata=user_metadata, user=user) s_edit_person_metadata = celery.signature( - 'cic_ussd.tasks.metadata.edit_person_metadata', - [blockchain_address, edited_metadata] + 'cic_ussd.tasks.metadata.create_person_metadata', + [blockchain_address, user_metadata] ) s_edit_person_metadata.apply_async(queue='cic-ussd') diff --git a/apps/cic-ussd/cic_ussd/translation.py b/apps/cic-ussd/cic_ussd/translation.py index 35fd1cd1..e512a5b3 100644 --- a/apps/cic-ussd/cic_ussd/translation.py +++ b/apps/cic-ussd/cic_ussd/translation.py @@ -19,4 +19,6 @@ def translation_for(key: str, preferred_language: Optional[str] = None, **kwargs """ if preferred_language: i18n.set('locale', preferred_language) + else: + i18n.set('locale', i18n.config.get('fallback')) return i18n.t(key, **kwargs) diff --git a/apps/cic-ussd/requirements.txt b/apps/cic-ussd/requirements.txt index 793d5021..b01d9d47 100644 --- a/apps/cic-ussd/requirements.txt +++ b/apps/cic-ussd/requirements.txt @@ -1,4 +1,4 @@ -cic_base[full_graph]~=0.1.2b2 -cic-eth~=0.11.0b9 -cic-notify~=0.4.0a4 +cic_base[full_graph]~=0.1.2b14 +cic-eth~=0.11.0b15 +cic-notify~=0.4.0a5 cic-types~=0.1.0a10 diff --git a/apps/cic-ussd/states/account_management_states.json b/apps/cic-ussd/states/account_management_states.json index 419ba157..456edd92 100644 --- a/apps/cic-ussd/states/account_management_states.json +++ b/apps/cic-ussd/states/account_management_states.json @@ -6,7 +6,10 @@ "enter_new_pin", "new_pin_confirmation", "display_user_metadata", - "standard_pin_authorization", + "name_edit_pin_authorization", + "gender_edit_pin_authorization", + "location_edit_pin_authorization", + "products_edit_pin_authorization", "account_balances_pin_authorization", "account_statement_pin_authorization", "account_balances" diff --git a/apps/cic-ussd/test_requirements.txt b/apps/cic-ussd/test_requirements.txt index 1ffd94fc..76aa808a 100644 --- a/apps/cic-ussd/test_requirements.txt +++ b/apps/cic-ussd/test_requirements.txt @@ -1,7 +1,11 @@ -pytest==6.0.1 +Faker==8.1.2 +faker-e164==0.1.0 +pytest==6.2.4 pytest-alembic==0.2.5 pytest-celery==0.0.0a1 pytest-cov==2.10.1 pytest-mock==3.3.1 +pytest-ordering==0.6 pytest-redis==2.0.0 -requests-mock==1.8.0 \ No newline at end of file +requests-mock==1.8.0 +tavern==1.14.2 \ No newline at end of file diff --git a/apps/cic-ussd/tests/conftest.py b/apps/cic-ussd/tests/conftest.py index 09c8ffc7..fa9389e3 100644 --- a/apps/cic-ussd/tests/conftest.py +++ b/apps/cic-ussd/tests/conftest.py @@ -6,6 +6,7 @@ from cic_types.pytest import * from tests.fixtures.config import * from tests.fixtures.db import * from tests.fixtures.celery import * +from tests.fixtures.integration import * from tests.fixtures.user import * from tests.fixtures.ussd_session import * from tests.fixtures.redis import * diff --git a/apps/cic-ussd/tests/fixtures/integration.py b/apps/cic-ussd/tests/fixtures/integration.py new file mode 100644 index 00000000..b4488dcc --- /dev/null +++ b/apps/cic-ussd/tests/fixtures/integration.py @@ -0,0 +1,249 @@ +# standard imports + +# external imports + +import pytest +from faker import Faker + +# local imports + +# test imports +from tests.helpers.accounts import phone_number, pin_number, session_id + + +fake = Faker() + + +@pytest.fixture(scope='function') +def generate_phone_number() -> str: + return phone_number() + + +@pytest.fixture(scope='function') +def generate_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_phone_number() -> str: + return phone_number() + + +@pytest.fixture(scope='session') +def second_account_phone_number() -> str: + return phone_number() + + +@pytest.fixture(scope='session') +def first_account_pin_number() -> str: + return pin_number() + + +@pytest.fixture(scope='session') +def second_account_pin_number() -> str: + return pin_number() + + +@pytest.fixture(scope='session') +def first_metadata_entry_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_metadata_entry_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_transaction_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_transaction_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_given_name() -> str: + return fake.first_name() + + +@pytest.fixture(scope='session') +def second_account_given_name() -> str: + return fake.first_name() + + +@pytest.fixture(scope='session') +def first_account_family_name() -> str: + return fake.last_name() + + +@pytest.fixture(scope='session') +def second_account_family_name() -> str: + return fake.last_name() + + +@pytest.fixture(scope='session') +def first_account_location() -> str: + return fake.city() + + +@pytest.fixture(scope='session') +def second_account_location() -> str: + return fake.city() + + +@pytest.fixture(scope='session') +def first_account_product() -> str: + return fake.color_name() + + +@pytest.fixture(scope='session') +def second_account_product() -> str: + return fake.color_name() + + +@pytest.fixture(scope='session') +def first_account_verify_balance_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_account_verify_balance_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_profile_management_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_profile_management_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_change_given_name() -> str: + return fake.first_name() + + +@pytest.fixture(scope='session') +def second_account_change_given_name() -> str: + return fake.first_name() + + +@pytest.fixture(scope='session') +def first_account_change_family_name() -> str: + return fake.last_name() + + +@pytest.fixture(scope='session') +def second_account_change_family_name() -> str: + return fake.last_name() + + +@pytest.fixture(scope='session') +def first_account_change_location() -> str: + return fake.city() + + +@pytest.fixture(scope='session') +def second_account_change_location() -> str: + return fake.city() + + +@pytest.fixture(scope='session') +def first_account_change_product() -> str: + return fake.color_name() + + +@pytest.fixture(scope='session') +def second_account_change_product() -> str: + return fake.color_name() + + +@pytest.fixture(scope='session') +def first_profile_management_session_id_1() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_profile_management_session_id_1() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_profile_management_session_id_2() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_profile_management_session_id_2() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_profile_management_session_id_3() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_profile_management_session_id_3() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_profile_management_session_id_4() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_profile_management_session_id_4() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_management_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_account_management_session_id() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_management_session_id_1() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def second_account_management_session_id_1() -> str: + return session_id() + + +@pytest.fixture(scope='session') +def first_account_new_pin_number() -> str: + return pin_number() + + +@pytest.fixture(scope='session') +def second_account_new_pin_number() -> str: + return pin_number() + + +@pytest.fixture(scope='session') +def gift_value(load_config): + return load_config.get('TEST_GIFT_VALUE') + + +@pytest.fixture(scope='session') +def server_url(load_config): + return load_config.get('TEST_SERVER_URL') + + +@pytest.fixture(scope='session') +def token_symbol(load_config): + return load_config.get('TEST_TOKEN_SYMBOL') diff --git a/apps/cic-ussd/tests/helpers/accounts.py b/apps/cic-ussd/tests/helpers/accounts.py new file mode 100644 index 00000000..9ba9bd78 --- /dev/null +++ b/apps/cic-ussd/tests/helpers/accounts.py @@ -0,0 +1,26 @@ +# standard imports +import random +import uuid + +# external imports +from faker import Faker +from faker_e164.providers import E164Provider + +# local imports + +# test imports + +fake = Faker() +fake.add_provider(E164Provider) + + +def phone_number() -> str: + return fake.e164('KE') + + +def session_id() -> str: + return uuid.uuid4().hex + + +def pin_number() -> int: + return random.randint(1000, 9999) diff --git a/apps/cic-ussd/tests/integration/ext/validator.py b/apps/cic-ussd/tests/integration/ext/validator.py new file mode 100644 index 00000000..cb8a1a3a --- /dev/null +++ b/apps/cic-ussd/tests/integration/ext/validator.py @@ -0,0 +1,11 @@ +import logging + + +logg = logging.getLogger() +logg.setLevel(logging.DEBUG) + + +def validate_response(response, expected_response): + """Makes sure that the response received matches the expected response""" + logg.debug(f'RESPONSE: {response.content.decode("utf-8")}') + assert response.content.decode('utf-8') == expected_response diff --git a/apps/cic-ussd/tests/integration/run.sh b/apps/cic-ussd/tests/integration/run.sh new file mode 100644 index 00000000..a6339c09 --- /dev/null +++ b/apps/cic-ussd/tests/integration/run.sh @@ -0,0 +1,2 @@ +#!/bin/bash +PYTHONPATH=. py.test --debug -vv --log-level debug -s --log-cli-level debug diff --git a/apps/cic-ussd/tests/integration/test_account_creation.tavern.yaml b/apps/cic-ussd/tests/integration/test_account_creation.tavern.yaml new file mode 100644 index 00000000..4fa83dd5 --- /dev/null +++ b/apps/cic-ussd/tests/integration/test_account_creation.tavern.yaml @@ -0,0 +1,466 @@ +test_name: Test the creation of accounts through the cic_user_ussd_server entrypoint. +marks: + - usefixtures: + - gift_value + - server_url + - token_symbol + - generate_session_id + - first_account_phone_number + - second_account_phone_number + - first_account_pin_number + - second_account_pin_number + - first_account_family_name + - second_account_family_name + - first_account_given_name + - second_account_given_name + - first_account_location + - second_account_location + - first_account_product + - second_account_product + - first_metadata_entry_session_id + - second_metadata_entry_session_id + - first + +stages: + - name: Initiate account creation process [first account]. + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{generate_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '175' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Your account is being created. You will receive an SMS when your account is ready.\nAkaunti yako ya Sarafu inatayarishwa. Utapokea ujumbe wa SMS akaunti yako ikiwa tayari.\n" + + - name: Initiate account creation process [second account]. + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{generate_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '175' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Your account is being created. You will receive an SMS when your account is ready.\nAkaunti yako ya Sarafu inatayarishwa. Utapokea ujumbe wa SMS akaunti yako ikiwa tayari.\n" + delay_after: 5 + + - name: Initaite account metadata entry [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '61' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Welcome to Sarafu Network\n1. English\n2. Kiswahili\n3. Help" + + - name: Initaite account metadata entry [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '61' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Welcome to Sarafu Network\n1. English\n2. Kiswahili\n3. Help" + + - name: Select preferred language [English] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '64' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter a new four number PIN for your account.\n0. Back" + + - name: Select preferred language [Kiswahili] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '71' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka pin mpya yenye nambari nne kwa akaunti yako\n0. Nyuma" + + - name: Enter pin number [{first_account_pin_number} - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '44' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter your four number PIN again\n0. Back" + + - name: Enter pin number [second_account_pin_number - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '31' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka PIN yako tena\n0. Nyuma" + + - name: Pin number confirmation [first_account_pin_number - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '28' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter first name\n0. Back" + + - name: Pin number confirmation [{second_account_pin_number} - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '37' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jina lako la kwanza\n0. Nyuma" + + - name: Enter first name [first_account_given_name - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '29' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter family name\n0. Back" + + - name: Enter first name [second_account_given_name - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '37' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jina lako la mwisho\n0. Nyuma" + + - name: Enter last name [first_account_family_name - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter gender\n1. Male\n2. Female\n3. Other\n0. Back" + + - name: Enter last name [second_account_family_name - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '64' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jinsia yako\n1. Mwanaume\n2. Mwanamke\n3. Nyngine\n0. Nyuma" + + - name: Select gender [Male - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '31' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter your location\n0. Back" + + - name: Select gender [Female - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '27' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka eneo lako\n0. Nyuma" + + - name: Enter location [first_account_location - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1*{first_account_location}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '55' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter a product or service you offer\n0. Back" + + - name: Enter location [second_account_location - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2*{second_account_location}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '42' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka bidhaa ama huduma unauza\n0. Nyuma" + + - name: Enter product [first_account_product - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_metadata_entry_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{first_account_pin_number}*{first_account_pin_number}*{first_account_given_name}*{first_account_family_name}*1*{first_account_location}*{first_account_product}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance {gift_value} {token_symbol}\n1. Send\n2. My Account\n3. Help" + delay_before: 10 + + - name: Enter product [second_account_product - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_metadata_entry_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*{second_account_pin_number}*{second_account_pin_number}*{second_account_given_name}*{second_account_family_name}*2*{second_account_location}*{second_account_product}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio {gift_value} {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + delay_before: 10 diff --git a/apps/cic-ussd/tests/integration/test_account_management.tavern.yaml b/apps/cic-ussd/tests/integration/test_account_management.tavern.yaml new file mode 100644 index 00000000..03a5a4df --- /dev/null +++ b/apps/cic-ussd/tests/integration/test_account_management.tavern.yaml @@ -0,0 +1,587 @@ +test_name: Test performing account management operations. +marks: + - usefixtures: + - server_url + - token_symbol + - first_account_pin_number + - second_account_pin_number + - first_account_phone_number + - second_account_phone_number + - first_account_management_session_id + - second_account_management_session_id + - first_account_management_session_id_1 + - second_account_management_session_id_1 + - first_account_new_pin_number + - second_account_new_pin_number + - fourth + +stages: + - name: Account management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Account management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Language change [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Choose language\n1. English\n2. Kiswahili\n0. Back" + + - name: Language change [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Chagua lugha\n1. Kingereza\n2. Kiswahili\n0. Nyuma" + + - name: Select language [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*2*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Asante kwa kutumia huduma." + + - name: Select language [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Thank you for using the service." + + - name: Second account management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 58.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Second account management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 42.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Second account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Second account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Check balance [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '49' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako kuona salio.\n0. Nyuma" + + - name: Check balance [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '50' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN to view balances\n0. Back" + + - name: Display balances [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio zako ni zifuatazo:\n salio: 58.00 {token_symbol}\n ushuru: {token_symbol}\n tuzo: {token_symbol}\n0. Nyuma" + + - name: Display balances [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Your balances are as follows:\n balance: 42.00 {token_symbol}\n fees: {token_symbol}\n rewards: {token_symbol}\n0. Back" + + - name: Resume account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Resume account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Change pin number [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}*0*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '34' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka nambari ya siri.\n0. Nyuma" + + - name: Change pin number [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}*0*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter current PIN.\n0. Back" + + - name: Enter old pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}*0*5*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '38' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka nambari ya siri mpya\n0. Nyuma" + + - name: Enter old pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}*0*5*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '42' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter your new four number PIN\n0. Back" + + - name: Enter new pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}*0*5*{first_account_pin_number}*{first_account_new_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '31' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka PIN yako tena\n0. Nyuma" + + - name: Enter new pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}*0*5*{second_account_pin_number}*{second_account_new_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '48' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter your new four number PIN again\n0. Back" + + - name: Enter new pin confirmation [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*3*{first_account_pin_number}*0*5*{first_account_pin_number}*{first_account_new_pin_number}*{first_account_new_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '91' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Ombi lako limetumwa. Utapokea uthibitishaji wa SMS kwa muda mfupi.\n00. Nyuma\n99. Ondoka" + + - name: Enter new pin confirmation [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*3*{second_account_pin_number}*0*5*{second_account_pin_number}*{second_account_new_pin_number}*{second_account_new_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '82' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Your request has been sent. You will receive an SMS shortly.\n00. Back\n99. Exit" diff --git a/apps/cic-ussd/tests/integration/test_profile_management.tavern.yaml b/apps/cic-ussd/tests/integration/test_profile_management.tavern.yaml new file mode 100644 index 00000000..274f0265 --- /dev/null +++ b/apps/cic-ussd/tests/integration/test_profile_management.tavern.yaml @@ -0,0 +1,1573 @@ +test_name: Test editing account profile data. +marks: + - usefixtures: + - server_url + - token_symbol + - first_account_pin_number + - second_account_pin_number + - first_account_phone_number + - second_account_phone_number + - first_account_family_name + - second_account_family_name + - first_account_given_name + - second_account_given_name + - first_account_location + - second_account_location + - first_account_product + - second_account_product + - first_profile_management_session_id + - second_profile_management_session_id + - first_account_change_family_name + - second_account_change_family_name + - first_account_change_given_name + - second_account_change_given_name + - first_account_change_location + - second_account_change_location + - first_account_change_product + - second_account_change_product + - first_profile_management_session_id_1 + - second_profile_management_session_id_1 + - first_profile_management_session_id_2 + - second_profile_management_session_id_2 + - first_profile_management_session_id_3 + - second_profile_management_session_id_3 + - first_profile_management_session_id_4 + - second_profile_management_session_id_4 + - third + +stages: + - name: Profile management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Profile management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Enter pin to view profile [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Enter pin to view profile [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Display profile [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Your details are:\n Name: {first_account_given_name} {first_account_family_name}\n Gender: Male\n Location: {first_account_location}\n You sell: {first_account_product}\n0. Back" + + - name: Display profile [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wako una maelezo yafuatayo:\n Jina: {second_account_given_name} {second_account_family_name}\n Jinsia: Mwanamke\n Eneo: {second_account_location}\n Unauza: {second_account_product}\n0. Nyuma" + + - name: Second profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{first_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Second profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Edit name [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '28' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter first name\n0. Back" + + - name: Edit name [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '37' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jina lako la kwanza\n0. Nyuma" + + - name: Enter given name [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{first_account_change_given_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '29' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter family name\n0. Back" + + - name: Enter given name [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{second_account_change_given_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '37' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jina lako la mwisho\n0. Nyuma" + + - name: Enter family name [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{first_account_change_given_name}*{first_account_change_family_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Enter family name [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{second_account_change_given_name}*{second_account_change_family_name}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Enter name change pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{first_account_change_given_name}*{first_account_change_family_name}*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Thank you for using the service." + + - name: Enter name change pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*1*{second_account_change_given_name}*{second_account_change_family_name}*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Asante kwa kutumia huduma." + + - name: Second profile management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Second profile management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Second account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Second account management [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Second profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Second profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Gender change [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter gender\n1. Male\n2. Female\n3. Other\n0. Back" + + - name: Gender change [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '64' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka jinsia yako\n1. Mwanaume\n2. Mwanamke\n3. Nyngine\n0. Nyuma" + + - name: Select gender [female - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*2*2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Select gender [male - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Enter gender change pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_1}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*2*2*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Thank you for using the service." + + - name: Enter gender change pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_1}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*2*1*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Asante kwa kutumia huduma." + + - name: Third profile management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Third profile management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Third account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Third account management [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Third profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Third profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Location change [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*3" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '31' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter your location\n0. Back" + + - name: Location change [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*3" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '27' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka eneo lako\n0. Nyuma" + + - name: Enter location change [first_account_change_location - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*3*{first_account_change_location}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Enter location change [second_account_change_location - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*3*{second_account_change_location}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Enter location change pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_2}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*3*{first_account_change_location}*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Thank you for using the service." + + - name: Enter location change pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_2}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*3*{second_account_change_location}*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Asante kwa kutumia huduma." + + - name: Fourth profile management start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Fourth profile management start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Fourth account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Fourth account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Fourth profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Fourth profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Product change [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*4" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '55' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter a product or service you offer\n0. Back" + + - name: Product change [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*4" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '42' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka bidhaa ama huduma unauza\n0. Nyuma" + + - name: Enter product change [first_account_change_product - first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*4*{first_account_change_product}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Enter product change [second_account_change_product - second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*4*{second_account_change_product}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Enter product change pin [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_3}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*4*{first_account_change_product}*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Thank you for using the service." + + - name: Enter product change pin [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_3}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*4*{second_account_change_product}*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "END Asante kwa kutumia huduma." + + - name: Fifth profile managment start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Fifth profile managment start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Fifth account management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '105' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My account\n1. My profile\n2. Change language\n3. Check balance\n4. Check statement\n5. Change PIN\n0. Back" + + - name: Fifth account management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '148' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Akaunti yangu\n1. Wasifu wangu\n2. Chagua lugha utakayotumia\n3. Angalia salio\n4. Angalia taarifa ya matumizi\n5. Badilisha nambari ya siri\n0. Nyuma" + + - name: Fifth profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Fifth profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2*1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Second enter pin to view profile [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Please enter your PIN\n0. Back" + + - name: Second enter pin to view profile [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '36' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Tafadhali weka PIN yako\n0. Nyuma" + + - name: Second display profile [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Your details are:\n Name: {first_account_change_given_name} {first_account_change_family_name}\n Gender: Female\n Location: {first_account_change_location}\n You sell: {first_account_change_product}\n0. Back" + + - name: Second display profile [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wako una maelezo yafuatayo:\n Jina: {second_account_change_given_name} {second_account_change_family_name}\n Jinsia: Mwanaume\n Eneo: {second_account_change_location}\n Unauza: {second_account_change_product}\n0. Nyuma" + + - name: Return to profile management menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{first_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '103' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON My profile\n1. Edit name\n2. Edit gender\n3. Edit location\n4. Edit products\n5. View my profile\n0. Back" + + - name: Return to profile management menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '104' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Wasifu wangu\n1. Weka jina\n2. Weka jinsia\n3. Weka eneo\n4. Weka bidhaa\n5. Angalia wasifu wako\n0. Nyuma" + + - name: Resume start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_profile_management_session_id_4}" + phoneNumber: "{first_account_phone_number}" + text: "2*1*5*{first_account_pin_number}*0*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Resume start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_profile_management_session_id_4}" + phoneNumber: "{second_account_phone_number}" + text: "2*1*5*{second_account_pin_number}*0*0" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" \ No newline at end of file diff --git a/apps/cic-ussd/tests/integration/test_transactions.tavern.yaml b/apps/cic-ussd/tests/integration/test_transactions.tavern.yaml new file mode 100644 index 00000000..9a50f012 --- /dev/null +++ b/apps/cic-ussd/tests/integration/test_transactions.tavern.yaml @@ -0,0 +1,282 @@ +test_name: Test that the two test accounts can trade with each other. +marks: + - usefixtures: + - gift_value + - server_url + - token_symbol + - first_account_family_name + - second_account_family_name + - first_account_given_name + - second_account_given_name + - first_account_phone_number + - second_account_phone_number + - first_account_pin_number + - second_account_pin_number + - first_transaction_session_id + - second_transaction_session_id + - first_account_verify_balance_session_id + - second_account_verify_balance_session_id + - second + +stages: + - name: Transactions start menu [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_transaction_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance {gift_value} {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Transactions start menu [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_transaction_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio {gift_value} {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" + + - name: Initate transcation attempt [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_transaction_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '30' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter phone number\n0. Back" + + - name: Initate transcation attempt [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_transaction_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "1" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '33' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka nambari ya simu\n0. Nyuma" + + - name: Enter phone number [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_transaction_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{second_account_phone_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '24' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Enter amount\n0. Back" + + - name: Enter phone number [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_transaction_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "1*{first_account_phone_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '25' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Weka kiwango\n0. Nyuma" + + - name: Enter transcation amount [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_transaction_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{second_account_phone_number}*17" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON {second_account_given_name} {second_account_family_name} {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_given_name} {first_account_family_name} {first_account_phone_number}.\nPlease enter your PIN to confirm.\n0. Back" + + - name: Enter transcation amount [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_transaction_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "1*{first_account_phone_number}*25" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON {first_account_given_name} {first_account_family_name} {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_given_name} {second_account_family_name} {second_account_phone_number}.\nTafadhali weka nambari yako ya siri kudhibitisha.\n0. Nyuma" + + - name: Pin to authorize transaction [first account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_transaction_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "1*{second_account_phone_number}*17*{first_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Your request has been sent. {second_account_given_name} {second_account_family_name} {second_account_phone_number} will receive 17.00 {token_symbol} from {first_account_given_name} {first_account_family_name} {first_account_phone_number}.\n00. Back\n99. Exit" + + - name: Pin to authorize transaction [second account] + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_transaction_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "1*{first_account_phone_number}*25*{second_account_pin_number}" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Ombi lako limetumwa. {first_account_given_name} {first_account_family_name} {first_account_phone_number} atapokea 25.00 {token_symbol} kutoka kwa {second_account_given_name} {second_account_family_name} {second_account_phone_number}.\n00. Nyuma\n99. Ondoka" + + - name: Verify balance changes [first account] + delay_before: 10 + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{first_account_verify_balance_session_id}" + phoneNumber: "{first_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '51' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Balance 58.00 {token_symbol}\n1. Send\n2. My Account\n3. Help" + + - name: Verify balance changes [second account] + delay_before: 10 + request: + url: "{server_url}" + data: + serviceCode: "*483*46#" + sessionId: "{second_account_verify_balance_session_id}" + phoneNumber: "{second_account_phone_number}" + text: "" + headers: + content-type: "application/x-www-form-urlencoded" + method: POST + response: + status_code: + - 200 + headers: + Content-Length: '56' + Content-Type: "text/plain" + verify_response_with: + function: ext.validator:validate_response + extra_kwargs: + expected_response: "CON Salio 42.00 {token_symbol}\n1. Tuma\n2. Akaunti yangu\n3. Usaidizi" \ No newline at end of file diff --git a/apps/cic-ussd/transitions/gender_setting_transitions.json b/apps/cic-ussd/transitions/gender_setting_transitions.json index 951be716..7881cdd7 100644 --- a/apps/cic-ussd/transitions/gender_setting_transitions.json +++ b/apps/cic-ussd/transitions/gender_setting_transitions.json @@ -4,12 +4,13 @@ "source": "enter_gender", "dest": "enter_location", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", - "conditions": "cic_ussd.state_machine.logic.validator.is_valid_gender_selection" + "conditions": "cic_ussd.state_machine.logic.validator.is_valid_gender_selection", + "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, { "trigger": "scan_data", "source": "enter_gender", - "dest": "standard_pin_authorization", + "dest": "gender_edit_pin_authorization", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", "conditions": [ "cic_ussd.state_machine.logic.validator.has_cached_user_metadata", @@ -18,15 +19,14 @@ }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "gender_edit_pin_authorization", "dest": "exit", "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", - "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute", - "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" + "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "gender_edit_pin_authorization", "dest": "exit_pin_blocked", "conditions": "cic_ussd.state_machine.logic.pin.is_locked_account" }, diff --git a/apps/cic-ussd/transitions/location_setting_transitions.json b/apps/cic-ussd/transitions/location_setting_transitions.json index d4197339..fa6ea52d 100644 --- a/apps/cic-ussd/transitions/location_setting_transitions.json +++ b/apps/cic-ussd/transitions/location_setting_transitions.json @@ -3,26 +3,26 @@ "trigger": "scan_data", "source": "enter_location", "dest": "enter_products", - "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data" + "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", + "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, { "trigger": "scan_data", "source": "enter_location", - "dest": "standard_pin_authorization", + "dest": "location_edit_pin_authorization", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", "conditions": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "location_edit_pin_authorization", "dest": "exit", "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", - "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute", - "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" + "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "location_edit_pin_authorization", "dest": "exit_pin_blocked", "conditions": "cic_ussd.state_machine.logic.pin.is_locked_account" } diff --git a/apps/cic-ussd/transitions/name_setting_transitions.json b/apps/cic-ussd/transitions/name_setting_transitions.json index 1cda4b84..38b5e58c 100644 --- a/apps/cic-ussd/transitions/name_setting_transitions.json +++ b/apps/cic-ussd/transitions/name_setting_transitions.json @@ -7,49 +7,28 @@ }, { "trigger": "scan_data", - "source": "enter_given_name", - "dest": "standard_pin_authorization", + "source": "enter_family_name", + "dest": "name_edit_pin_authorization", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", "conditions": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, - { - "trigger": "scan_data", - "source": "standard_pin_authorization", - "dest": "exit", - "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", - "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute", - "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" - }, - { - "trigger": "scan_data", - "source": "standard_pin_authorization", - "dest": "exit_pin_blocked", - "conditions": "cic_ussd.state_machine.logic.pin.is_locked_account" - }, { "trigger": "scan_data", "source": "enter_family_name", "dest": "enter_gender", - "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data" - }, - { - "trigger": "scan_data", - "source": "enter_family_name", - "dest": "standard_pin_authorization", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", - "conditions": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" - }, - { - "trigger": "scan_data", - "source": "standard_pin_authorization", - "dest": "exit", - "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", - "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute", "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "name_edit_pin_authorization", + "dest": "exit", + "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", + "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute" + }, + { + "trigger": "scan_data", + "source": "name_edit_pin_authorization", "dest": "exit_pin_blocked", "conditions": "cic_ussd.state_machine.logic.pin.is_locked_account" } diff --git a/apps/cic-ussd/transitions/pin_setting_transitions.json b/apps/cic-ussd/transitions/pin_setting_transitions.json index 2d904be0..6b5e797b 100644 --- a/apps/cic-ussd/transitions/pin_setting_transitions.json +++ b/apps/cic-ussd/transitions/pin_setting_transitions.json @@ -9,14 +9,14 @@ "trigger": "scan_data", "source": "enter_current_pin", "dest": "exit_pin_blocked", - "conditions": "cic_ussd.state_machine.logic.menu.is_blocked_pin" + "conditions": "cic_ussd.state_machine.logic.pin.is_blocked_pin" }, { "trigger": "scan_data", "source": "enter_new_pin", "dest": "new_pin_confirmation", "after": "cic_ussd.state_machine.logic.pin.save_initial_pin_to_session_data", - "conditions": "cic_ussd.state_machine.logic.menu.is_valid_new_pin" + "conditions": "cic_ussd.state_machine.logic.pin.is_valid_new_pin" }, { "trigger": "scan_data", @@ -28,7 +28,7 @@ "source": "new_pin_confirmation", "dest": "complete", "conditions": "cic_ussd.state_machine.logic.pin.pins_match", - "after": "cic_ussd.state_machine.logic.menu.complete_pin_change" + "after": "cic_ussd.state_machine.logic.pin.complete_pin_change" }, { "trigger": "scan_data", diff --git a/apps/cic-ussd/transitions/products_setting_transitions.json b/apps/cic-ussd/transitions/products_setting_transitions.json index b4bb8b1d..ac105842 100644 --- a/apps/cic-ussd/transitions/products_setting_transitions.json +++ b/apps/cic-ussd/transitions/products_setting_transitions.json @@ -2,7 +2,7 @@ { "trigger": "scan_data", "source": "enter_products", - "dest": "standard_pin_authorization", + "dest": "products_edit_pin_authorization", "conditions": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata", "after": "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data" }, @@ -13,18 +13,19 @@ "after": [ "cic_ussd.state_machine.logic.user.save_metadata_attribute_to_session_data", "cic_ussd.state_machine.logic.user.save_complete_user_metadata" - ] + ], + "unless": "cic_ussd.state_machine.logic.validator.has_cached_user_metadata" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "products_edit_pin_authorization", "dest": "exit", "conditions": "cic_ussd.state_machine.logic.pin.is_authorized_pin", "after": "cic_ussd.state_machine.logic.user.edit_user_metadata_attribute" }, { "trigger": "scan_data", - "source": "standard_pin_authorization", + "source": "products_edit_pin_authorization", "dest": "exit_pin_blocked", "conditions": "cic_ussd.state_machine.logic.pin.is_locked_account" } diff --git a/apps/cic-ussd/transitions/user_metadata_transitions.json b/apps/cic-ussd/transitions/user_metadata_transitions.json index 7ee8cab0..dff068f6 100644 --- a/apps/cic-ussd/transitions/user_metadata_transitions.json +++ b/apps/cic-ussd/transitions/user_metadata_transitions.json @@ -8,7 +8,7 @@ { "trigger": "scan_data", "source": "metadata_management", - "dest": "enter_age", + "dest": "enter_gender", "conditions": "cic_ussd.state_machine.logic.menu.menu_two_selected" }, { diff --git a/apps/cic-ussd/var/lib/locale/ussd.en.yml b/apps/cic-ussd/var/lib/locale/ussd.en.yml index 8e9c3e42..d1f0653b 100644 --- a/apps/cic-ussd/var/lib/locale/ussd.en.yml +++ b/apps/cic-ussd/var/lib/locale/ussd.en.yml @@ -6,7 +6,7 @@ en: 2. Kiswahili 3. Help initial_pin_entry: |- - CON Please enter a new four number PIN for your account. + CON Please enter a new four number PIN for your account. 0. Back initial_pin_confirmation: |- CON Enter your four number PIN again @@ -76,7 +76,10 @@ en: CON Enter current PIN. You have %{remaining_attempts} attempts remaining. 0. Back enter_new_pin: |- - CON Enter new PIN again + CON Enter your new four number PIN + 0. Back + new_pin_confirmation: |- + CON Enter your new four number PIN again 0. Back transaction_pin_authorization: first: |- @@ -107,6 +110,34 @@ en: retry: |- CON Please enter your PIN. You have %{remaining_attempts} attempts remaining 0. Back + name_edit_pin_authorization: + first: |- + CON Please enter your PIN + 0. Back + retry: |- + CON Please enter your PIN. You have %{remaining_attempts} attempts remaining + 0. Back + gender_edit_pin_authorization: + first: |- + CON Please enter your PIN + 0. Back + retry: |- + CON Please enter your PIN. You have %{remaining_attempts} attempts remaining + 0. Back + location_edit_pin_authorization: + first: |- + CON Please enter your PIN + 0. Back + retry: |- + CON Please enter your PIN. You have %{remaining_attempts} attempts remaining + 0. Back + products_edit_pin_authorization: + first: |- + CON Please enter your PIN + 0. Back + retry: |- + CON Please enter your PIN. You have %{remaining_attempts} attempts remaining + 0. Back account_balances: |- CON Your balances are as follows: balance: %{operational_balance} %{token_symbol} diff --git a/apps/cic-ussd/var/lib/locale/ussd.sw.yml b/apps/cic-ussd/var/lib/locale/ussd.sw.yml index 57fea950..a40db2b7 100644 --- a/apps/cic-ussd/var/lib/locale/ussd.sw.yml +++ b/apps/cic-ussd/var/lib/locale/ussd.sw.yml @@ -21,7 +21,7 @@ sw: CON Weka jinsia yako 1. Mwanaume 2. Mwanamke - 3. Nyngine + 3. Nyngine 0. Nyuma enter_location: |- CON Weka eneo lako @@ -61,7 +61,7 @@ sw: Jina: %{full_name} Jinsia: %{gender} Eneo: %{location} - Unauza: %{user_bio} + Unauza: %{products} 0. Nyuma select_preferred_language: |- CON Chagua lugha @@ -78,6 +78,9 @@ sw: enter_new_pin: |- CON Weka nambari ya siri mpya 0. Nyuma + new_pin_confirmation: |- + CON Weka PIN yako tena + 0. Nyuma transaction_pin_authorization: first: |- CON %{recipient_information} atapokea %{transaction_amount} %{token_symbol} kutoka kwa %{sender_information}. @@ -86,9 +89,9 @@ sw: retry: |- CON Weka nambari ya siri. Una majaribio %{remaining_attempts} yaliyobaki. 0. Nyuma - standard_pin_authorization: + display_metadata_pin_authorization: first: |- - CON Tafadhali weka PIN yako. + CON Tafadhali weka PIN yako 0. Nyuma retry: |- CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. @@ -107,12 +110,40 @@ sw: retry: |- CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. 0. Nyuma + name_edit_pin_authorization: + first: |- + CON Tafadhali weka PIN yako + 0. Nyuma + retry: |- + CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. + 0. Nyuma + gender_edit_pin_authorization: + first: |- + CON Tafadhali weka PIN yako + 0. Nyuma + retry: |- + CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. + 0. Nyuma + location_edit_pin_authorization: + first: |- + CON Tafadhali weka PIN yako + 0. Nyuma + retry: |- + CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. + 0. Nyuma + products_edit_pin_authorization: + first: |- + CON Tafadhali weka PIN yako + 0. Nyuma + retry: |- + CON Tafadhali weka PIN yako. Una majaribio %{remaining_attempts} yaliyobaki. + 0. Nyuma account_balances: |- CON Salio zako ni zifuatazo: - salio: %{operational_balance} - ushuru: %{tax} - tuzo: %{bonus} - 0. Back + salio: %{operational_balance} %{token_symbol} + ushuru: %{tax} %{token_symbol} + tuzo: %{bonus} %{token_symbol} + 0. Nyuma first_transaction_set: |- CON %{first_transaction_set} 1. Mbele