Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
first pass at testeos
Browse files Browse the repository at this point in the history
  • Loading branch information
Buddy Deck committed Jan 15, 2019
1 parent dcdaa63 commit 37ca01e
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 52 deletions.
16 changes: 15 additions & 1 deletion eospy/command_line.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import argparse
from .cleos import Cleos
from .testeos import TestEos
import json

def console_print(data):
Expand All @@ -8,7 +9,7 @@ def console_print(data):
def cleos():
parser = argparse.ArgumentParser(description='Command Line Interface to EOSIO via python')
parser.add_argument('--api-version','-v', type=str, default='v1', action='store', dest='api_version')
parser.add_argument('--url', '-u', type=str, action='store', default='https://api.eosnewyork.io', dest='url')
parser.add_argument('--url', '-u', type=str, action='store', default='https://proxy.eosnode.tools', dest='url')
parser.add_argument('--time-out', type=int, action='store', default=30, dest='timeout')
subparsers = parser.add_subparsers(dest='subparser')
# get
Expand Down Expand Up @@ -138,3 +139,16 @@ def cleos():
timeout=args.timeout)
console_print(resp)

def testeos():
parser = argparse.ArgumentParser(description='EOSIO testing harness')
parser.add_argument('--yaml','-y', type=str, action='store', required=True, dest='yaml_loc')
parser.add_argument('--tests','-t', nargs='*', action='store', default="all", dest='tests')
# process args
args = parser.parse_args()

tester = TestEos(args.yaml_loc)
if args.tests == 'all':
tester.run_test_all()
else:
for test in args.tests:
tester.run_test_one(test)
136 changes: 88 additions & 48 deletions eospy/schema.py
Original file line number Diff line number Diff line change
@@ -1,82 +1,82 @@
import colander

class BaseSchema(colander.SchemaNode) :
class BaseSchema(colander.SchemaNode):
required = True

class StringSchema(BaseSchema) :
class StringSchema(BaseSchema):
schema_type = colander.String

# str schemas
class NameSchema(StringSchema) : pass
class AccountNameSchema(NameSchema) : pass
class PermissionNameSchema(NameSchema) : pass
class ActionNameSchema(NameSchema) : pass
class TableNameSchema(NameSchema) : pass
class ScopeNameSchema(NameSchema) : pass
class NameSchema(StringSchema): pass
class AccountNameSchema(NameSchema): pass
class PermissionNameSchema(NameSchema): pass
class ActionNameSchema(NameSchema): pass
class TableNameSchema(NameSchema): pass
class ScopeNameSchema(NameSchema): pass

# boolean
class BooleanSchema(BaseSchema) :
class BooleanSchema(BaseSchema):
schema_type = colander.Bool

# numeric

class IntSchema(BaseSchema) :
class IntSchema(BaseSchema):
schema_type = colander.Int

class HexBytesSchema(StringSchema) :
class HexBytesSchema(StringSchema):
missing = colander.drop

class DataSchema(StringSchema) : pass
class DataSchema(StringSchema): pass

# Authority/permission
class ThresholdSchema(IntSchema) : pass
class ThresholdSchema(IntSchema): pass

class PublicKeySchema(StringSchema) : pass
class PublicKeySchema(StringSchema): pass

class WeightSchema(IntSchema) : pass
class WeightSchema(IntSchema): pass

class KeyWeightSchema(colander.MappingSchema):
key = PublicKeySchema()
weight = WeightSchema()

class KeyWeightsSchema(colander.SequenceSchema) :
class KeyWeightsSchema(colander.SequenceSchema):
key = KeyWeightSchema()

class PermissionLevelSchema(colander.MappingSchema) :
class PermissionLevelSchema(colander.MappingSchema):
actor = AccountNameSchema()
permission = PermissionNameSchema()

class PermissionLevelsSchema(colander.SequenceSchema) :
class PermissionLevelsSchema(colander.SequenceSchema):
permission = PermissionLevelSchema()

class PermissionLevelWeightSchema(colander.MappingSchema) :
class PermissionLevelWeightSchema(colander.MappingSchema):
permission = PermissionLevelSchema()
weight = WeightSchema()

class PermissionLevelWeightsSchema(colander.SequenceSchema) :
class PermissionLevelWeightsSchema(colander.SequenceSchema):
permission_level = PermissionLevelWeightSchema()

class WaitSecSchema(IntSchema) : pass
class WaitSecSchema(IntSchema): pass

class WaitWeightSchema(colander.MappingSchema) :
class WaitWeightSchema(colander.MappingSchema):
wait_sec = WaitSecSchema()
weight = WeightSchema()

class WaitWeightsSchema(colander.SequenceSchema) :
class WaitWeightsSchema(colander.SequenceSchema):
waits = WaitWeightSchema()

class AuthoritySchema(colander.MappingSchema) :
class AuthoritySchema(colander.MappingSchema):
threshold = ThresholdSchema()
keys = KeyWeightsSchema()
accounts = PermissionLevelWeightsSchema()
waits = WaitWeightsSchema()

class PermNameSchema(BaseSchema) :
class PermNameSchema(BaseSchema):
schema_type = colander.String

class ParentSchema(StringSchema) : pass
class ParentSchema(StringSchema): pass

class PermissionSchema(colander.MappingSchema) :
class PermissionSchema(colander.MappingSchema):
perm_name = PermNameSchema()
parent = ParentSchema()
required_auth = AuthoritySchema()
Expand All @@ -85,26 +85,26 @@ class PermissionSchema(colander.MappingSchema) :
# message actions attributes
#############################

class ActionSchema(colander.MappingSchema) :
class ActionSchema(colander.MappingSchema):
account = AccountNameSchema()
name = ActionNameSchema()
authorization = PermissionLevelsSchema()
hex_data = HexBytesSchema()
data = DataSchema()

class ActionsSchema(colander.SequenceSchema) :
class ActionsSchema(colander.SequenceSchema):
action = ActionSchema()

class ContextActionsSchema(colander.SequenceSchema) :
class ContextActionsSchema(colander.SequenceSchema):
action = ActionSchema()
default = []
missing = []

class ExtensionSchema(colander.MappingSchema) :
class ExtensionSchema(colander.MappingSchema):
type = IntSchema()
data = HexBytesSchema()

class ExtensionsSchema(colander.SequenceSchema) :
class ExtensionsSchema(colander.SequenceSchema):
extension = ExtensionSchema()
default = []
missing = []
Expand All @@ -113,25 +113,25 @@ class ExtensionsSchema(colander.SequenceSchema) :
# message header attributes
#############################

class TimeSchema(BaseSchema) :
class TimeSchema(BaseSchema):
schema_type = colander.DateTime

class RefBlockNumSchema(IntSchema) : pass
class RefBlockPrefixSchema(IntSchema) : pass
class NetUsageWordsSchema(IntSchema) :
class RefBlockNumSchema(IntSchema): pass
class RefBlockPrefixSchema(IntSchema): pass
class NetUsageWordsSchema(IntSchema):
default = 0
missing = 0
class MaxCpuUsageMsSchema(IntSchema) :
class MaxCpuUsageMsSchema(IntSchema):
default = 0
missing = 0
class DelaySecSchema(IntSchema) :
class DelaySecSchema(IntSchema):
default = 0
missing = 0

class SignaturesSchema(colander.Sequence) :
class SignaturesSchema(colander.Sequence):
signatures = StringSchema()

class TransactionSchema(colander.MappingSchema) :
class TransactionSchema(colander.MappingSchema):
# header
expiration = TimeSchema()
ref_block_num = RefBlockNumSchema()
Expand All @@ -145,25 +145,25 @@ class TransactionSchema(colander.MappingSchema) :
transaction_extensions = ExtensionsSchema()

# signed transaction
class SignedTransactionSchema(colander.MappingSchema) :
class SignedTransactionSchema(colander.MappingSchema):
compression = StringSchema
transaction = TransactionSchema()
signatures = SignaturesSchema()

# final transaction
class PushTransactionSchema(colander.MappingSchema) :
class PushTransactionSchema(colander.MappingSchema):
transaction_id = StringSchema()
broadcast = BooleanSchema()
transaction = SignedTransactionSchema()

class TransactionsSchema(colander.SequenceSchema) :
class TransactionsSchema(colander.SequenceSchema):
transactions = TransactionSchema()

#############################
# get info
#############################

class ChainInfoSchema(colander.MappingSchema) :
class ChainInfoSchema(colander.MappingSchema):
server_version = StringSchema()
chain_id = StringSchema()
head_block_num = IntSchema()
Expand All @@ -181,19 +181,19 @@ class ChainInfoSchema(colander.MappingSchema) :
# get block
#############################

class ProducerSchema(colander.SchemaNode) :
class ProducerSchema(colander.SchemaNode):
schema_type = colander.String
missing = 'null'
default = 'null'
required = False

class HeaderExtsSchema(colander.SequenceSchema) :
class HeaderExtsSchema(colander.SequenceSchema):
header_extensions = ExtensionsSchema()

class BlockExtsSchema(colander.SequenceSchema) :
class BlockExtsSchema(colander.SequenceSchema):
block_extensions = ExtensionsSchema()

class BlockInfoSchema(colander.MappingSchema) :
class BlockInfoSchema(colander.MappingSchema):
timestamp = TimeSchema()
producer = StringSchema()
confirmed = IntSchema()
Expand All @@ -210,3 +210,43 @@ class BlockInfoSchema(colander.MappingSchema) :
id = StringSchema()
block_num = IntSchema()
ref_block_prefix = IntSchema()

#############################
# eosytest
#############################

def test_param_validator(node, value):
if not isinstance(value, dict):
raise colander.Invalid(node, '{} is not a valid dictionary'.format(value))

class TestEnvSchema(colander.MappingSchema):
url = StringSchema()

class TestAuthSchema(colander.MappingSchema):
actor = StringSchema()
permission = StringSchema()
key = StringSchema()

class TestActionSchema(colander.MappingSchema):
action = StringSchema()
contract = StringSchema()
authorization = TestAuthSchema()
parameters = colander.SchemaNode(
colander.Mapping(unknown='preserve'),
validator=test_param_validator
)
exception = BooleanSchema()

class TestActionsSchema(colander.SequenceSchema):
actions = TestActionSchema()

class TestSchema(colander.MappingSchema):
name = StringSchema()
actions = TestActionsSchema()

class TestsSchema(colander.SequenceSchema):
tests = TestSchema()

class TestDocSchema(colander.MappingSchema):
environment = TestEnvSchema()
tests = TestsSchema()
77 changes: 77 additions & 0 deletions eospy/testeos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os
import yaml
from .cleos import Cleos
from .schema import TestDocSchema

class TestEos:

def __init__(self, yaml_location):
self._documents = []
self._results = []
if os.path.isdir(yaml_location):
for file in os.listdir(yaml_location):
if file.endswith('.yml') or file.endswith('.yaml'):
full_path = os.path.join(yaml_location, file)
with open(full_path) as yaml_file:
self._documents += yaml.load_all(yaml_file)
else:
with open(yaml_location) as yaml_file:
self._documents += yaml.load_all(yaml_file)
validator = TestDocSchema()
for doc in self._documents:
validator.deserialize(doc)

def run_test(self, url, test):
print('Running: {}'.format(test['name']))
rslts = {'name': test['name'], 'results': True, "message": "successful" }
ce = Cleos(url)
for action in test['actions']:
payload = {
"account": action['contract'],
"name": action['action'],
"authorization": [{
"actor": action['authorization']['actor'],
"permission": action['authorization']['permission'],
}],
}
data = ce.abi_json_to_bin(payload['account'], payload['name'], action['parameters'])
payload['data']=data['binargs']
trx = {'actions': [payload]}
try:
ce.push_transaction(trx, action['authorization']['key'])
except Exception as ex:
if(not action['exception']):
rslts['results'] = False
rslts['message'] = str(ex)
self._results.append(rslts)

def run_test_one(self, name):
for doc in self._documents:
url = doc['environment']['url']
for test in doc['tests']:
if test['name'] == name:
self.run_test(url, test)

def run_test_all(self):
for doc in self._documents:
url = doc['environment']['url']
for test in doc['tests']:
self.run_test(url, test)

def _get_results(self, successful=True, failed=True):
return_rslts = []
for rslt in self._results:
if not rslt['results'] and failed:
return_rslts.append(rslt)
if rslt['results'] and successful:
return_rslts.append(rslt)
return return_rslts

def get_all_results(self):
return self._get_results(True, True)

def get_failed_results(self):
return self._get_results(False, True)

def get_successful_results(self):
return self._get_results(True, False)
Loading

0 comments on commit 37ca01e

Please sign in to comment.