Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat/staking tests #29

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Feat/staking tests #29

wants to merge 13 commits into from

Conversation

Mohsinsiddi
Copy link
Collaborator

Description

Adds comprehensive testing for service staking functionality, including rewards claiming, termination, and staking state verification. The changes add a new test file test_staking_service.py and updates existing test infrastructure to support staking-specific test cases.

Key Changes

  • Added new test_staking_service.py with staking-specific test classes and utilities:

    • StakingOptionParser for handling staking choice prompts
    • StakingStatusChecker for verifying staking states
    • StakingBaseTestService extending base test service with staking capabilities
    • Support for fast-forwarding blockchain time for testing reward accrual
    • Comprehensive test flow including service health, staking verification, and termination
  • Updated test_run_service.py:

    • Added Gnosis chain support for token funding
    • Enhanced funding handler patterns for cross-chain compatibility
    • Removed outdated Optimus-specific delay

Testing Flow

The new testing framework verifies:

  1. Initial service health check
  2. Staking status verification
  3. Service stopping
  4. Time fast-forwarding for reward accrual
  5. Service termination
  6. Post-termination staking status
  7. Shutdown log verification

Dependencies

  • Temporarily using local path for middleware (will be removed before merge):
    olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-app.git", rev = "c5e385009081f924de9241454b7777b82f7e798a"}
    olas-operate-middleware = { path ="/Users/siddi_404/Solulab/OLAS/middleware/olas-operate-app"}
  • Python version requirement: >=3.9,<3.12
  • Additional dev dependencies for testing

How to Test

  1. Ensure environment variables are set for RPC endpoints (GNOSIS_RPC_URL, etc.)
  2. Set TEST_PASSWORD environment variable
  3. Run: poetry run pytest -v tests/test_staking_service.py -s --log-cli-level=INFO

Notes

  • Excluded mech, meme, optimus, and modius agents from staking tests
  • Added robust error handling and logging throughout testing process
  • Will clean up middleware dependency configuration before final merge

TODO Before Merge

  • Remove local path dependency for middleware
  • Keep only git source with specific revision

pyproject.toml Outdated Show resolved Hide resolved
tests/test_staking_service.py Outdated Show resolved Hide resolved
tests/test_staking_service.py Outdated Show resolved Hide resolved
tests/test_staking_service.py Outdated Show resolved Hide resolved

cls._setup_complete = True

def assert_service_stopped(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we re-use from BaseTestService

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Comment on lines 287 to 289
if not staking_program_id or staking_program_id == "no_staking":
test_instance.logger.info("Service is not using staking")
return True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably pass the expected staking program in the function parameter, and match that here

tests/test_staking_service.py Outdated Show resolved Hide resolved
Comment on lines 192 to 220
def get_staking_state(self, service_id: int, staking_address: str) -> StakingState:
"""Get the current staking state for a service."""
try:
# Get staking state using ledger API
state = StakingState(
self.staking_contract.get_instance(
ledger_api=self.ledger_api,
contract_address=staking_address,
)
.functions.getStakingState(service_id)
.call()
)

self.logger.info(f"Got staking state for service {service_id}: {state}")
return state

except Exception as e:
self.logger.error(f"Failed to get staking state: {e}")
raise

def check_service_staking(self, service_id: int, staking_address: str) -> bool:
"""Check if service is properly staked."""
try:
state = self.get_staking_state(service_id, staking_address)
return state == StakingState.STAKED

except Exception as e:
self.logger.error(f"Staking check failed: {e}")
return False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please re-use these functions from operate


return settings

class StakingStatusChecker:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this entire class is re-inventing the functions that are already present in operate, please import and use them

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please check this again, needed keys for this so had to init it

Comment on lines 50 to 132
def parse_staking_options(output: str, logger: logging.Logger) -> List[Dict]:
"""Parse staking options and their available slots from CLI output."""
options = []
logger.info("Starting to parse staking options...")

# Pattern to match option lines with slots
pattern = r'(\d+)\)\s*(.*?)\s*\(available slots\s*:\s*([∞\d]+)\)'
matches = re.finditer(pattern, output)

for match in matches:
number = int(match.group(1))
name = match.group(2).strip()
slots_str = match.group(3)
slots = float('inf') if slots_str == '∞' else int(slots_str)

option = {
'number': number,
'name': name,
'slots': slots
}
options.append(option)
logger.debug(f"Found option: {option}")

logger.info(f"Found {len(options)} staking options")
return options

@staticmethod
def select_staking_option(options: List[Dict], logger: logging.Logger) -> str:
"""Select option with maximum available slots, never selecting option 1."""
if not options:
logger.warning("No options parsed, defaulting to option 2")
return "2"

# Filter out option 1 and options with no slots
valid_options = [
opt for opt in options
if opt['number'] != 1 and opt['slots'] > 0
]

if not valid_options:
logger.warning("No valid options with available slots, defaulting to option 2")
return "2"

# Select option with maximum available slots
selected = max(valid_options, key=lambda x: x['slots'])
logger.info(f"Selected option {selected['number']}: {selected['name']} with {selected['slots']} slots")

return str(selected['number'])

def handle_staking_choice(output: str, logger: logging.Logger) -> str:
"""Handle staking choice based on available slots."""
try:
parser = StakingOptionParser()
options = parser.parse_staking_options(output, logger)
selected = parser.select_staking_option(options, logger)

# Final safety check
if selected == "1":
logger.warning("Safety check caught attempt to select option 1, forcing option 2")
return "2"

logger.info(f"Final choice: option {selected}")
return selected

except Exception as e:
logger.error(f"Error in staking choice handler: {str(e)}")
logger.warning("Falling back to option 2")
return "2"

def get_staking_config_settings(config_path: str) -> dict:
"""Get config specific settings with updated staking handler."""

# Get original settings from main test script
settings = get_config_specific_settings(config_path)

# Remove any default staking choice patterns if they exist
if r"Enter your choice" in settings["prompts"]:
settings["prompts"].pop(r"Enter your choice", None)

# Add our custom staking handler with highest priority
settings["prompts"][r"Enter your choice \(1 - \d+\):"] = handle_staking_choice

return settings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make these functions the members of StakingBaseTestService

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@OjusWiZard OjusWiZard changed the base branch from main to feat/migration-script February 5, 2025 19:48
@OjusWiZard OjusWiZard changed the base branch from feat/migration-script to main February 5, 2025 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants