class BaseTestCase(unittest.TestCase): """ Base class for test cases. All test cases can feel free to implement this. """ def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ E2E_CONFIG['test-network']['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG['test-network']['docker']['compose_file_tls'] self.client = Client('test/fixtures/network.json') self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') self.start_test_env() def tearDown(self): self.shutdown_test_env() def check_logs(self): cli_call([ "docker-compose", "-f", self.compose_file_path, "logs", "--tail=200" ]) def start_test_env(self): cli_call(["docker-compose", "-f", self.compose_file_path, "up", "-d"]) def shutdown_test_env(self): cli_call(["docker-compose", "-f", self.compose_file_path, "down"])
class ClientBase: """Base class for a Hyperledger Fabric client.""" def __init__(self, profile, channel_name, org_name, peer_name, user_name): self.client = Client(profile) self._channel_name = channel_name self._org_name = org_name self._peer_name = peer_name self._user_name = user_name self._user = self.client.get_user(self._org_name, self._user_name) endpoint = self.client.get_net_info('peers', self._peer_name, 'url') tlscert = self.client.get_net_info('peers', self._peer_name, 'tlsCACerts', 'path') loop = asyncio.get_event_loop() peer = create_peer(endpoint=endpoint, tls_cacerts=tlscert) loop.run_until_complete( self.client.init_with_discovery(self._user, peer, self._channel_name)) self._channel = self.client.new_channel(self._channel_name) @property def channel_name(self): return self._channel_name @property def channel(self): return self._channel @property def org_name(self): return self._org_name @property def peer_name(self): return self._peer_name @property def user_name(self): return self._user_name @property def user(self): return self._user
class E2ePrivateDataTest(BaseTestCase): def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ E2E_CONFIG['test-network']['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG['test-network']['docker']['compose_file_tls'] self.config_yaml = \ E2E_CONFIG['test-network']['channel-artifacts']['config_yaml'] self.channel_profile = \ E2E_CONFIG['test-network']['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/network.json') self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') # Boot up the testing network self.shutdown_test_env() self.start_test_env() time.sleep(1) def tearDown(self): super(E2ePrivateDataTest, self).tearDown() async def channel_create(self): """ Create an channel for further testing. :return: """ logger.info(f"E2E: Channel creation start: name={self.channel_name}") # By default, self.user is the admin of org1 response = await self.client.channel_create( 'orderer.example.com', self.channel_name, self.user, config_yaml=self.config_yaml, channel_profile=self.channel_profile) self.assertTrue(response) logger.info(f"E2E: Channel creation done: name={self.channel_name}") async def channel_join(self): """ Join peers of two orgs into an existing channels :return: """ logger.info(f"E2E: Channel join start: name={self.channel_name}") # channel must already exist when to join channel = self.client.get_channel(self.channel_name) self.assertIsNotNone(channel) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, 'Admin') response = await self.client.channel_join( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], orderer='orderer.example.com') self.assertTrue(response) # Verify the ledger exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run( 'test -f ' '/var/hyperledger/production/ledgersData/chains/' f'chains/{self.channel_name}' '/blockfile_000000') self.assertEqual(code, 0, "Local ledger not exists") logger.info(f"E2E: Channel join done: name={self.channel_name}") async def channel_update_anchors(self): orgs = ["org1.example.com", "org2.example.com"] anchors = [ 'test/fixtures/e2e_cli/channel-artifacts/' + msporg + 'anchors.tx' for msporg in ['Org1MSP', 'Org2MSP'] ] for org, anchortx in zip(orgs, anchors): org_admin = self.client.get_user(org, "Admin") response = await self.client.channel_update("orderer.example.com", self.channel_name, org_admin, config_tx=anchortx) self.assertTrue(response) async def chaincode_install(self): """ Test installing an example chaincode to peer """ logger.info("E2E: Chaincode install start") cc = f'/var/hyperledger/production/chaincodes/{CC_NAME}.{CC_VERSION}' # uncomment for testing with packaged_cc # create packaged chaincode before for having same id # code_package = package_chaincode(CC_PATH, CC_TYPE_GOLANG) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: # simulate possible different chaincode archive based on timestamp time.sleep(2) org_admin = self.client.get_user(org, "Admin") responses = await self.client.chaincode_install( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], cc_path=CC_PATH, cc_name=CC_NAME, cc_version=CC_VERSION, # packaged_cc=code_package ) self.assertTrue(responses) # Verify the cc pack exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer_container = dc.containers.get(peer + '.' + org) code, output = peer_container.exec_run(f'test -f {cc}') self.assertEqual(code, 0, "chaincodes pack not exists") logger.info("E2E: chaincode install done") async def chaincode_instantiate(self): """ Test instantiating an example chaincode to peer """ logger.info("E2E: Chaincode instantiation start") org = "org1.example.com" policy = s2d().parse("OR('Org1MSP.member', 'Org2MSP.member')") collections_config = [{ "name": "collectionMarbles", "policy": s2d().parse("OR('Org1MSP.member','Org2MSP.member')"), "requiredPeerCount": 0, "maxPeerCount": 1, "blockToLive": 1000000, "memberOnlyRead": True }, { "name": "collectionMarblePrivateDetails", "policy": s2d().parse("OR('Org1MSP.member')"), "requiredPeerCount": 0, "maxPeerCount": 1, "blockToLive": 5, "memberOnlyRead": True }] org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_instantiate( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=None, cc_name=CC_NAME, cc_version=CC_VERSION, cc_endorsement_policy=policy, collections_config=collections_config, wait_for_event=True) logger.info( "E2E: Chaincode instantiation response {}".format(response)) policy = { 'version': 0, 'rule': { 'n_out_of': { 'n': 1, 'rules': [{ 'signed_by': 0 }, { 'signed_by': 1 }] } }, 'identities': [ { 'principal_classification': 'ROLE', 'principal': { 'msp_identifier': 'Org1MSP', 'role': 'MEMBER' } }, { 'principal_classification': 'ROLE', 'principal': { 'msp_identifier': 'Org2MSP', 'role': 'MEMBER' } }, ] } self.assertEqual(response['name'], CC_NAME) self.assertEqual(response['version'], CC_VERSION) self.assertEqual(response['policy'], policy) logger.info("E2E: chaincode instantiation done") async def chaincode_invoke(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode invoke start") orgs = ["org1.example.com"] marble = json.dumps({ "name": "marble1", "color": "blue", "size": 35, "owner": "tom", "price": 99 }).encode() for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_invoke( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], fcn='initMarble', args=None, cc_name=CC_NAME, wait_for_event=True, wait_for_event_timeout=120, transient_map={"marble": marble}) self.assertFalse(response) # Wait for gossip private data time.sleep(5) logger.info("E2E: chaincode invoke done") async def chaincode_query(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode query start") orgs = ["org1.example.com"] args = ["marble1"] res = { "color": "blue", "docType": "marble", "name": "marble1", "owner": "tom", "size": 35 } resp = { "docType": "marblePrivateDetails", "name": "marble1", "price": 99 } for org in ["org1.example.com", "org2.example.com"]: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], fcn="readMarble", args=args, cc_name=CC_NAME) self.assertEqual(json.loads(response), res) orgs = ["org1.example.com"] args = ["marble1"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], fcn="readMarblePrivateDetails", args=args, cc_name=CC_NAME) self.assertEqual(json.loads(response), resp) orgs = ["org2.example.com"] args = ["marble1"] error = "does not have read access permission" for org in orgs: org_admin = self.client.get_user(org, "Admin") with self.assertRaises(Exception) as context: response = await self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], fcn="readMarblePrivateDetails", args=args, cc_name=CC_NAME) self.assertTrue(error in str(context.exception)) logger.info("E2E: chaincode query done") async def query_installed_chaincodes(self): """ Test query installed chaincodes on peer :return: """ logger.info("E2E: Query installed chaincode start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") responses = await self.client.query_installed_chaincodes( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(responses[0].chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(responses[0].chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(responses[0].chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def query_instantiated_chaincodes(self): """ Test query instantiated chaincodes on peer :return: """ logger.info("E2E: Query instantiated chaincode start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") responses = await self.client.query_instantiated_chaincodes( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) self.assertTrue(len(responses) >= 1) self.assertEqual(responses[0].chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(responses[0].chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(responses[0].chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def get_channel_config(self): """ Test get channel config on peer :return: """ logger.info(f"E2E: Get channel {self.channel_name} config start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") responses = await self.client.get_channel_config( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org]) self.assertEqual(responses[0].config.sequence, 1, "Get Config Failed") logger.info("E2E: Query installed chaincode done") async def get_channel_config_with_orderer(self, chname=SYSTEM_CHANNEL_NAME): """ Test get channel config on orderer :return: """ logger.info(f"E2E: Get channel {chname} config start") orgs = ["orderer.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.get_channel_config_with_orderer( orderer='orderer.example.com', requestor=org_admin, channel_name=chname, ) self.assertEqual(response['config']['sequence'], '0', "Get Config Failed") logger.info(f"E2E: Get channel {chname} config done") def test_in_sequence(self): loop = asyncio.get_event_loop() logger.info("\n\nE2E testing started...") self.client.new_channel(SYSTEM_CHANNEL_NAME) loop.run_until_complete(self.get_channel_config_with_orderer()) loop.run_until_complete(self.channel_create()) loop.run_until_complete(self.channel_join()) loop.run_until_complete(self.channel_update_anchors()) loop.run_until_complete(self.get_channel_config()) loop.run_until_complete(self.chaincode_install()) loop.run_until_complete(self.query_installed_chaincodes()) loop.run_until_complete(self.chaincode_instantiate()) loop.run_until_complete(self.query_instantiated_chaincodes()) loop.run_until_complete(self.chaincode_invoke()) loop.run_until_complete(self.chaincode_query()) logger.info("E2E private data all test cases done\n\n")
class E2eTest(BaseTestCase): def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ E2E_CONFIG['test-network']['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG['test-network']['docker']['compose_file_mutual_tls'] self.config_yaml = \ E2E_CONFIG['test-network']['channel-artifacts']['config_yaml'] self.channel_profile = \ E2E_CONFIG['test-network']['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/network-mutual-tls.json') self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') # Boot up the testing network self.shutdown_test_env() self.start_test_env() time.sleep(1) def tearDown(self): super(E2eTest, self).tearDown() def channel_create(self): """ Create an channel for further testing. :return: """ logger.info("E2E: Channel creation start: name={}".format( self.channel_name)) # By default, self.user is the admin of org1 response = self.client.channel_create( 'orderer.example.com', self.channel_name, self.user, config_yaml=self.config_yaml, channel_profile=self.channel_profile) self.assertTrue(response) logger.info("E2E: Channel creation done: name={}".format( self.channel_name)) def channel_join(self): """ Join peers of two orgs into an existing channels :return: """ logger.info("E2E: Channel join start: name={}".format( self.channel_name)) # channel must already exist when to join channel = self.client.get_channel(self.channel_name) self.assertIsNotNone(channel) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, 'Admin') response = self.client.channel_join( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], orderer='orderer.example.com') self.assertTrue(response) # Verify the ledger exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run( 'test -f ' '/var/hyperledger/production/ledgersData/chains/chains/{}' '/blockfile_000000'.format(self.channel_name)) self.assertEqual(code, 0, "Local ledger not exists") logger.info("E2E: Channel join done: name={}".format( self.channel_name)) def chaincode_install(self): """ Test installing an example chaincode to peer :return: """ logger.info("E2E: Chaincode install start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.chaincode_install( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], cc_path=CC_PATH, cc_name=CC_NAME, cc_version=CC_VERSION) self.assertTrue(response) # Verify the cc pack exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run( 'test -f ' '/var/hyperledger/production/chaincodes/example_cc.1.0') self.assertEqual(code, 0, "chaincodes pack not exists") logger.info("E2E: chaincode install done") def chaincode_install_fail(self): pass def chaincode_instantiate(self): """ Test instantiating an example chaincode to peer :return: """ logger.info("E2E: Chaincode instantiation start") orgs = ["org1.example.com"] args = ['a', '200', 'b', '300'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.chaincode_instantiate( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION) logger.info( "E2E: Chaincode instantiation response {}".format(response)) self.assertTrue(response) logger.info("E2E: chaincode instantiation done") def chaincode_invoke(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode invoke start") orgs = ["org1.example.com"] args = ['a', 'b', '100'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.chaincode_invoke( requestor=org_admin, channel_name=self.channel_name, peers=['peer1.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION, wait_for_event=True) self.assertEqual(response, '') logger.info("E2E: chaincode invoke done") def chaincode_query(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode query start") orgs = ["org1.example.com"] args = ['b'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION) self.assertEqual(response, '400') # 300 + 100 logger.info("E2E: chaincode query done") def query_installed_chaincodes(self): """ Test query installed chaincodes on peer :return: """ logger.info("E2E: Query installed chaincode start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_installed_chaincodes( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(response.chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(response.chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(response.chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") def query_channels(self): """ Test querying channel :return: """ logger.info("E2E: Query channel start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_channels( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(response.channels[0].channel_id, 'businesschannel', "Query failed") logger.info("E2E: Query channel done") def query_info(self): """ Test querying information on the state of the Channel :return: """ logger.info("E2E: Query info start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(response.height, 3, "Query failed") logger.info("E2E: Query info done") def query_block_by_txid(self): """ Test querying block by tx id :return: """ logger.info("E2E: Query block by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash) tx_id = response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id') response = self.client.query_block_by_txid( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id) self.assertEqual( response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id'), tx_id, "Query failed") logger.info("E2E: Query block by tx id done") def query_block_by_hash(self): """ Test querying block by block hash :return: """ logger.info("E2E: Query block by block hash start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) previous_block_hash = response.previousBlockHash current_block_hash = response.currentBlockHash response = self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=current_block_hash) self.assertEqual( response['header']['previous_hash'].decode('utf-8'), previous_block_hash.hex(), "Query failed") logger.info("E2E: Query block by block hash done") def query_block(self): """ Test querying block by block number :return: """ logger.info("E2E: Query block by block number start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_block( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_number='0') self.assertEqual(response['header']['number'], 0, "Query failed") self.blockheader = response['header'] logger.info("E2E: Query block by block number done") def query_transaction(self): """ Test querying transaction by tx id :return: """ logger.info("E2E: Query transaction by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash) tx_id = response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id') response = self.client.query_transaction( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id) self.assertEqual( response.get('transaction_envelope').get('payload').get( 'header').get('channel_header').get('channel_id'), self.channel_name, "Query failed") logger.info("E2E: Query transaction by tx id done") def query_instantiated_chaincodes(self): """ Test query instantiated chaincodes on peer :return: """ logger.info("E2E: Query installed chaincode start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.query_instantiated_chaincodes( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org]) self.assertEqual(response.chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(response.chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(response.chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") def get_channel_config(self): """ Test get channel config on peer :return: """ logger.info("E2E: Get channel config start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = self.client.get_channel_config( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org]) self.assertEqual(response.config.sequence, 1, "Get Config Failed") logger.info("E2E: Query installed chaincode done") def get_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) org_admin = self.client.get_user(org, 'Admin') events = self.client.get_events(org_admin, peer, self.channel_name, filtered=True, behavior='FAIL_IF_NOT_READY') self.assertEqual(len(events), 4) self.assertEqual(events[0]['number'], 0) self.assertEqual(events[0]['channel_id'], self.channel_name) filtered_transaction = events[0]['filtered_transactions'][0] self.assertEqual(filtered_transaction['tx_validation_code'], 'VALID') self.assertEqual(filtered_transaction['txid'], '') self.assertEqual(filtered_transaction['type'], 'CONFIG') self.assertEqual(events[2]['number'], 2) filtered_transaction = events[2]['filtered_transactions'][0] self.assertEqual(filtered_transaction['tx_validation_code'], 'VALID') self.assertEqual(filtered_transaction['type'], 'ENDORSER_TRANSACTION') # test missing block is present data = {'channel_id': '', 'filtered_transactions': [], 'number': 0} self.assertEqual(events[len(events) - 1], data) def test_in_sequence(self): logger.info("\n\nE2E testing started...") self.channel_create() self.channel_join() self.chaincode_install() self.chaincode_install_fail() self.chaincode_instantiate() self.chaincode_invoke() self.chaincode_query() self.query_instantiated_chaincodes() self.query_installed_chaincodes() self.query_channels() self.query_info() self.query_block_by_txid() self.query_block_by_hash() self.query_block() self.query_transaction() self.get_channel_config() self.get_events() logger.info("E2E all test cases done\n\n")
class E2eMutualTest(BaseTestCase): def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ E2E_CONFIG['test-network']['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG['test-network']['docker']['compose_file_mutual_tls'] self.config_yaml = \ E2E_CONFIG['test-network']['channel-artifacts']['config_yaml'] self.channel_profile = \ E2E_CONFIG['test-network']['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/network-mutual-tls.json') with open('test/fixtures/network-mutual-tls.json') as f: self.network_info = json.load(f) self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') # Boot up the testing network self.shutdown_test_env() self.start_test_env() time.sleep(1) def tearDown(self): super(E2eMutualTest, self).tearDown() async def channel_create(self): """ Create an channel for further testing. :return: """ logger.info("E2E: Channel creation start: name={}".format( self.channel_name)) # By default, self.user is the admin of org1 node_info = self.network_info['peers']['peer0.org1.example.com'] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.channel_create( 'orderer.example.com', self.channel_name, self.user, config_yaml=self.config_yaml, channel_profile=self.channel_profile) self.assertTrue(response) logger.info(f"E2E: Channel creation done: name={self.channel_name}") async def channel_join(self): """ Join peers of two orgs into an existing channels :return: """ logger.info(f"E2E: Channel join start: name={self.channel_name}") # channel must already exist when to join channel = self.client.get_channel(self.channel_name) self.assertIsNotNone(channel) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, 'Admin') node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.channel_join( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], orderer='orderer.example.com', ) self.assertTrue(response) # Verify the ledger exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run( 'test -f ' '/var/hyperledger/production/ledgersData/chains/' f'chains/{self.channel_name}' '/blockfile_000000') self.assertEqual(code, 0, "Local ledger not exists") logger.info(f"E2E: Channel join done: name={self.channel_name}") async def chaincode_install(self): """ Test installing an example chaincode to peer :return: """ logger.info("E2E: Chaincode install start") cc = f'/var/hyperledger/production/chaincodes/{CC_NAME}.{CC_VERSION}' # create packaged chaincode before for having same id code_package = package_chaincode(CC_PATH, CC_TYPE_GOLANG) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) responses = await self.client.chaincode_install( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], cc_path=CC_PATH, cc_name=CC_NAME, cc_version=CC_VERSION, packaged_cc=code_package) self.assertTrue(responses) # Verify the cc pack exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer_container = dc.containers.get(peer + '.' + org) code, output = peer_container.exec_run(f'test -f {cc}') self.assertEqual(code, 0, "chaincodes pack not exists") logger.info("E2E: chaincode install done") def chaincode_install_fail(self): pass async def chaincode_instantiate(self): """ Test instantiating an example chaincode to peer :return: """ logger.info("E2E: Chaincode instantiation start") org = "org1.example.com" args = ['a', '200', 'b', '300'] policy = { 'identities': [ { 'role': { 'name': 'member', 'mspId': 'Org1MSP' } }, # {'role': {'name': 'admin', 'mspId': 'Org1MSP'}}, ], 'policy': { '1-of': [ { 'signed-by': 0 }, # {'signed-by': 1}, ] } } org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.chaincode_instantiate( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION, cc_endorsement_policy=policy, wait_for_event=True) logger.info( "E2E: Chaincode instantiation response {}".format(response)) policy = { 'version': 0, 'rule': { 'n_out_of': { 'n': 1, 'rules': [ { 'signed_by': 0 }, # {'signed_by': 1} ] } }, 'identities': [ { 'principal_classification': 'ROLE', 'principal': { 'msp_identifier': 'Org1MSP', 'role': 'MEMBER' } }, # { # 'principal_classification': 'ROLE', # 'principal': { # 'msp_identifier': 'Org1MSP', # 'role': 'ADMIN' # } # }, ] } self.assertEqual(response['name'], CC_NAME) self.assertEqual(response['version'], CC_VERSION) self.assertEqual(response['policy'], policy) logger.info("E2E: chaincode instantiation done") async def chaincode_invoke(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode invoke start") orgs = ["org1.example.com"] args = ['a', 'b', '100'] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.chaincode_invoke( requestor=org_admin, channel_name=self.channel_name, peers=['peer1.' + org], args=args, cc_name=CC_NAME, wait_for_event=True, cc_pattern="^invoked*" # for chaincode event ) self.assertEqual(response, '400') logger.info("E2E: chaincode invoke done") async def chaincode_invoke_fail(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode invoke fail start") orgs = ["org2.example.com"] args = ['a', 'b', '100'] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) with self.assertRaises(Exception) as e: await self.client.chaincode_invoke( requestor=org_admin, channel_name=self.channel_name, peers=['peer1.' + org], args=args, cc_name=CC_NAME, wait_for_event=True, wait_for_event_timeout=120, cc_pattern="^invoked*" # for chaincode event ) self.assertEqual(e.exception.args[0], ['ENDORSEMENT_POLICY_FAILURE']) logger.info("E2E: chaincode invoke fail done") async def chaincode_channel_event_hub(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode Channel Event Hub test start") def onEvent(cc_event, block_number, tx_id, tx_status): self.ceh.unregisterChaincodeEvent(self.cr1) self.ceh.unregisterChaincodeEvent(self.cr2) self.ceh.unregisterChaincodeEvent(self.cr3) self.ceh.disconnect() orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") # register extra chaincode event channel = self.client.get_channel(self.channel_name) target_peer = self.client.get_peer('peer1.' + org) self.ceh = channel.newChannelEventHub(target_peer, org_admin) stream = self.ceh.connect() self.cr1 = self.ceh.registerChaincodeEvent(CC_NAME, 'invoked') self.cr2 = self.ceh.registerChaincodeEvent(CC_NAME, 'invoked') self.cr3 = self.ceh.registerChaincodeEvent(CC_NAME, 'invoked', onEvent=onEvent) await asyncio.wait_for(asyncio.gather(stream, return_exceptions=True), timeout=120) logger.info("E2E: Chaincode Channel Event Hub test done") async def chaincode_query(self, orgs=None): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode query start") if orgs is None: orgs = ["org1.example.com"] args = ['b'] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME) self.assertEqual(response, '400') # 300 + 100 logger.info("E2E: chaincode query done") async def query_installed_chaincodes(self): """ Test query installed chaincodes on peer :return: """ logger.info("E2E: Query installed chaincode start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) responses = await self.client.query_installed_chaincodes( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(responses[0].chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(responses[0].chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(responses[0].chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def query_channels(self): """ Test querying channel :return: """ logger.info("E2E: Query channel start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_channels( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(response.channels[0].channel_id, self.channel_name, "Query failed") logger.info("E2E: Query channel done") async def query_info(self): """ Test querying information on the state of the Channel :return: """ logger.info("E2E: Query info start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual(response.height, 4, "Query failed") logger.info("E2E: Query info done") async def query_block_by_txid(self): """ Test querying block by tx id :return: """ logger.info("E2E: Query block by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash) tx_id = response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id') response = await self.client.query_block_by_txid( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id) self.assertEqual( response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id'), tx_id, "Query failed") logger.info("E2E: Query block by tx id done") async def query_block_by_hash(self): """ Test querying block by block hash :return: """ logger.info("E2E: Query block by block hash start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) previous_block_hash = response.previousBlockHash current_block_hash = response.currentBlockHash response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=current_block_hash) self.assertEqual( response['header']['previous_hash'].decode('utf-8'), previous_block_hash.hex(), "Query failed") logger.info("E2E: Query block by block hash done") async def query_block(self): """ Test querying block by block number :return: """ logger.info("E2E: Query block by block number start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_block( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_number='0') self.assertEqual(response['header']['number'], 0, "Query failed") self.blockheader = response['header'] logger.info("E2E: Query block by block number done") async def query_transaction(self): """ Test querying transaction by tx id :return: """ logger.info("E2E: Query transaction by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash) tx_id = response.get('data').get('data')[0].get('payload').get( 'header').get('channel_header').get('tx_id') response = await self.client.query_transaction( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id) self.assertEqual( response.get('transaction_envelope').get('payload').get( 'header').get('channel_header').get('channel_id'), self.channel_name, "Query failed") logger.info("E2E: Query transaction by tx id done") async def query_instantiated_chaincodes(self): """ Test query instantiated chaincodes on peer :return: """ logger.info("E2E: Query instantiated chaincode start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) responses = await self.client.query_instantiated_chaincodes( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org]) self.assertTrue(len(responses) >= 1) self.assertEqual(responses[0].chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual(responses[0].chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual(responses[0].chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def get_channel_config(self): """ Test get channel config on peer :return: """ logger.info(f"E2E: Get channel {self.channel_name} config start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) responses = await self.client.get_channel_config( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org]) self.assertEqual(responses[0].config.sequence, 1, "Get Config Failed") logger.info("E2E: Query installed chaincode done") async def get_channel_config_with_orderer(self, chname=SYSTEM_CHANNEL_NAME): """ Test get channel config on orderer :return: """ logger.info(f"E2E: Get channel {chname} config start") orgs = ["orderer.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") node_info = self.network_info['orderers'][org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) response = await self.client.get_channel_config_with_orderer( orderer='orderer.example.com', requestor=org_admin, channel_name=chname, ) self.assertEqual(response['config']['sequence'], '0', "Get Config Failed") logger.info(f"E2E: Get channel {chname} config done") def onFilteredEvent(self, block): self.filtered_blocks.append(block) async def get_filtered_block_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) org_admin = self.client.get_user(org, 'Admin') channel = self.client.get_channel(self.channel_name) channel_event_hub = channel.newChannelEventHub(peer, org_admin) stream = channel_event_hub.connect(filtered=True, start='oldest', stop='newest') self.filtered_blocks = [] channel_event_hub.registerBlockEvent(unregister=False, onEvent=self.onFilteredEvent) try: await shield(stream) except Exception: pass channel_event_hub.disconnect() self.assertEqual(len(self.filtered_blocks), 4) block = self.filtered_blocks[0] self.assertEqual(block['number'], 0) self.assertEqual(block['channel_id'], self.channel_name) filtered_transaction = block['filtered_transactions'][0] self.assertEqual(filtered_transaction['tx_validation_code'], 'VALID') self.assertEqual(filtered_transaction['txid'], '') self.assertEqual(filtered_transaction['type'], 'CONFIG') def onFullEvent(self, block): self.blocks.append(block) async def get_full_block_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) node_info = self.network_info['peers']['peer0.' + org] set_tls = self.client.set_tls_client_cert_and_key( node_info['clientKey']['path'], node_info['clientCert']['path']) self.assertTrue(set_tls) org_admin = self.client.get_user(org, 'Admin') channel = self.client.get_channel(self.channel_name) channel_event_hub = channel.newChannelEventHub(peer, org_admin) stream = channel_event_hub.connect(filtered=False, start='oldest', stop='newest') self.blocks = [] channel_event_hub.registerBlockEvent(unregister=False, onEvent=self.onFullEvent) try: await shield(stream) except Exception: pass channel_event_hub.disconnect() self.assertEqual(len(self.blocks), 4) block = self.blocks[0] self.assertEqual(block['header']['number'], 0) block = self.blocks[2] self.assertEqual(block['header']['number'], 2) action = block['data']['data'][0]['payload']['data']['actions'][0] ppl_r_p = action['payload']['action']['proposal_response_payload'] events_obj = ppl_r_p['extension']['events'] self.assertEqual(events_obj['event_name'], 'invoked') self.assertEqual(events_obj['chaincode_id'], CC_NAME) self.assertEqual(events_obj['payload'], b'400') def onTxEvent(self, tx_id, status, block_number): o = {'status': status, 'block_number': block_number} if tx_id == 'all': if tx_id not in self.txs: self.txs[tx_id] = [] self.txs[tx_id] += [o] else: self.txs[tx_id] = o async def get_tx_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) org_admin = self.client.get_user(org, 'Admin') channel = self.client.get_channel(self.channel_name) channel_event_hub = channel.newChannelEventHub(peer, org_admin) stream = channel_event_hub.connect(start='oldest', stop='newest', filtered=False) self.txs = {} channel_event_hub.registerTxEvent('all', onEvent=self.onTxEvent) try: await shield(stream) except Exception: pass channel_event_hub.disconnect() self.assertEqual(len(self.txs['all']), 4) def test_in_sequence(self): loop = asyncio.get_event_loop() logger.info("\n\nE2E testing started...") self.client.new_channel(SYSTEM_CHANNEL_NAME) loop.run_until_complete(self.get_channel_config_with_orderer()) loop.run_until_complete(self.channel_create()) loop.run_until_complete(self.channel_join()) loop.run_until_complete(self.get_channel_config()) loop.run_until_complete(self.chaincode_install()) self.chaincode_install_fail() loop.run_until_complete(self.query_installed_chaincodes()) loop.run_until_complete(self.chaincode_instantiate()) loop.run_until_complete(self.query_instantiated_chaincodes()) loop.run_until_complete(self.chaincode_invoke()) loop.run_until_complete(self.chaincode_invoke_fail()) loop.run_until_complete(self.chaincode_channel_event_hub()) loop.run_until_complete(self.chaincode_query()) loop.run_until_complete(self.query_channels()) loop.run_until_complete(self.query_info()) loop.run_until_complete(self.query_block_by_txid()) loop.run_until_complete(self.query_block_by_hash()) loop.run_until_complete(self.query_block()) loop.run_until_complete(self.query_transaction()) loop.run_until_complete(self.get_filtered_block_events()) loop.run_until_complete(self.get_full_block_events()) loop.run_until_complete(self.get_tx_events()) logger.info("E2E all test cases done\n\n")
class E2eTest(BaseTestCase): def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath(os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ E2E_CONFIG['test-network']['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG['test-network']['docker']['compose_file_mutual_tls'] self.config_yaml = \ E2E_CONFIG['test-network']['channel-artifacts']['config_yaml'] self.channel_profile = \ E2E_CONFIG['test-network']['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/network-mutual-tls.json') self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') # Boot up the testing network self.shutdown_test_env() self.start_test_env() time.sleep(1) def tearDown(self): super(E2eTest, self).tearDown() async def channel_create(self): """ Create an channel for further testing. :return: """ logger.info("E2E: Channel creation start: name={}".format( self.channel_name)) # By default, self.user is the admin of org1 response = await self.client.channel_create( 'orderer.example.com', self.channel_name, self.user, config_yaml=self.config_yaml, channel_profile=self.channel_profile) self.assertTrue(response) logger.info("E2E: Channel creation done: name={}".format( self.channel_name)) async def channel_join(self): """ Join peers of two orgs into an existing channels :return: """ logger.info("E2E: Channel join start: name={}".format( self.channel_name)) # channel must already exist when to join channel = self.client.get_channel(self.channel_name) self.assertIsNotNone(channel) orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, 'Admin') response = await self.client.channel_join( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], orderer='orderer.example.com' ) self.assertTrue(response) # Verify the ledger exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run( 'test -f ' '/var/hyperledger/production/ledgersData/chains/chains/{}' '/blockfile_000000'.format(self.channel_name)) self.assertEqual(code, 0, "Local ledger not exists") logger.info("E2E: Channel join done: name={}".format( self.channel_name)) async def chaincode_install(self): """ Test installing an example chaincode to peer :return: """ logger.info("E2E: Chaincode install start") cc = f'/var/hyperledger/production/chaincodes/{CC_NAME}.{CC_VERSION}' orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") responses = await self.client.chaincode_install( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], cc_path=CC_PATH, cc_name=CC_NAME, cc_version=CC_VERSION ) self.assertTrue(responses) # Verify the cc pack exists now in the peer node dc = docker.from_env() for peer in ['peer0', 'peer1']: peer0_container = dc.containers.get(peer + '.' + org) code, output = peer0_container.exec_run(f'test -f {cc}') self.assertEqual(code, 0, "chaincodes pack not exists") logger.info("E2E: chaincode install done") def chaincode_install_fail(self): pass async def chaincode_instantiate(self): """ Test instantiating an example chaincode to peer :return: """ logger.info("E2E: Chaincode instantiation start") orgs = ["org1.example.com"] args = ['a', '200', 'b', '300'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_instantiate( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION, wait_for_event=True ) logger.info( "E2E: Chaincode instantiation response {}".format(response)) self.assertTrue(response) logger.info("E2E: chaincode instantiation done") async def chaincode_invoke(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode invoke start") orgs = ["org1.example.com"] args = ['a', 'b', '100'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_invoke( requestor=org_admin, channel_name=self.channel_name, peers=['peer1.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION, wait_for_event=True, cc_pattern="^invoked*" # for chaincode event ) self.assertEqual(response, '400') logger.info("E2E: chaincode invoke done") async def chaincode_query(self): """ Test invoking an example chaincode to peer :return: """ logger.info("E2E: Chaincode query start") orgs = ["org1.example.com"] args = ['b'] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.chaincode_query( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org], args=args, cc_name=CC_NAME, cc_version=CC_VERSION ) self.assertEqual(response, '400') # 300 + 100 logger.info("E2E: chaincode query done") async def query_installed_chaincodes(self): """ Test query installed chaincodes on peer :return: """ logger.info("E2E: Query installed chaincode start") orgs = ["org1.example.com", "org2.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_installed_chaincodes( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual( response.chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual( response.chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual( response.chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def query_channels(self): """ Test querying channel :return: """ logger.info("E2E: Query channel start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_channels( requestor=org_admin, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual( response.channels[0].channel_id, 'businesschannel', "Query failed") logger.info("E2E: Query channel done") async def query_info(self): """ Test querying information on the state of the Channel :return: """ logger.info("E2E: Query info start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) self.assertEqual( response.height, 3, "Query failed") logger.info("E2E: Query info done") async def query_block_by_txid(self): """ Test querying block by tx id :return: """ logger.info("E2E: Query block by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash ) tx_id = response.get('data').get('data')[0].get( 'payload').get('header').get( 'channel_header').get('tx_id') response = await self.client.query_block_by_txid( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id ) self.assertEqual( response.get('data').get('data')[0].get( 'payload').get('header').get( 'channel_header').get('tx_id'), tx_id, "Query failed") logger.info("E2E: Query block by tx id done") async def query_block_by_hash(self): """ Test querying block by block hash :return: """ logger.info("E2E: Query block by block hash start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) previous_block_hash = response.previousBlockHash current_block_hash = response.currentBlockHash response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=current_block_hash ) self.assertEqual( response['header']['previous_hash'].decode('utf-8'), previous_block_hash.hex(), "Query failed") logger.info("E2E: Query block by block hash done") async def query_block(self): """ Test querying block by block number :return: """ logger.info("E2E: Query block by block number start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_block( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_number='0' ) self.assertEqual( response['header']['number'], 0, "Query failed") self.blockheader = response['header'] logger.info("E2E: Query block by block number done") async def query_transaction(self): """ Test querying transaction by tx id :return: """ logger.info("E2E: Query transaction by tx id start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.query_info( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], ) response = await self.client.query_block_by_hash( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], block_hash=response.currentBlockHash ) tx_id = response.get('data').get('data')[0].get( 'payload').get('header').get( 'channel_header').get('tx_id') response = await self.client.query_transaction( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org], tx_id=tx_id ) self.assertEqual( response.get('transaction_envelope').get('payload').get( 'header').get('channel_header').get('channel_id'), self.channel_name, "Query failed") logger.info("E2E: Query transaction by tx id done") async def query_instantiated_chaincodes(self): """ Test query instantiated chaincodes on peer :return: """ logger.info("E2E: Query instantiated chaincode start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") responses = await self.client.query_instantiated_chaincodes( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org] ) self.assertTrue(len(responses) >= 1) self.assertEqual( responses[0].chaincodes[0].name, CC_NAME, "Query failed") self.assertEqual( responses[0].chaincodes[0].version, CC_VERSION, "Query failed") self.assertEqual( responses[0].chaincodes[0].path, CC_PATH, "Query failed") logger.info("E2E: Query installed chaincode done") async def get_channel_config(self): """ Test get channel config on peer :return: """ logger.info("E2E: Get channel config start") orgs = ["org1.example.com"] for org in orgs: org_admin = self.client.get_user(org, "Admin") response = await self.client.get_channel_config( requestor=org_admin, channel_name=self.channel_name, peers=['peer0.' + org, 'peer1.' + org] ) self.assertEqual(response.config.sequence, 1, "Get Config Failed") logger.info("E2E: Query installed chaincode done") def onFilteredEvent(self, block): self.filtered_blocks.append(block) async def get_filtered_block_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) org_admin = self.client.get_user(org, 'Admin') channel = self.client.get_channel(self.channel_name) channel_event_hub = channel.newChannelEventHub(peer, org_admin) stream = channel_event_hub.connect(filtered=True, start=0, stop=None) self.filtered_blocks = [] channel_event_hub.registerBlockEvent(unregister=False, onEvent=self.onFilteredEvent) await stream # will wait until empty block self.assertEqual(len(self.filtered_blocks), 4) block = self.filtered_blocks[0] self.assertEqual(block['number'], 0) self.assertEqual(block['channel_id'], self.channel_name) filtered_transaction = block['filtered_transactions'][0] self.assertEqual(filtered_transaction['tx_validation_code'], 'VALID') self.assertEqual(filtered_transaction['txid'], '') self.assertEqual(filtered_transaction['type'], 'CONFIG') # test missing block is present data = {'channel_id': '', 'filtered_transactions': [], 'number': 0} filtered_block = self.filtered_blocks[len(self.filtered_blocks) - 1] self.assertEqual(filtered_block, data) def onFullEvent(self, block): self.blocks.append(block) async def get_full_block_events(self): org = 'org1.example.com' peer = self.client.get_peer('peer0.' + org) org_admin = self.client.get_user(org, 'Admin') channel = self.client.get_channel(self.channel_name) channel_event_hub = channel.newChannelEventHub(peer, org_admin) stream = channel_event_hub.connect(start=0, stop=None, filtered=False) self.blocks = [] channel_event_hub.registerBlockEvent(unregister=False, onEvent=self.onFullEvent) await stream self.assertEqual(len(self.blocks), 4) block = self.blocks[0] self.assertEqual(block['header']['number'], 0) block = self.blocks[2] self.assertEqual(block['header']['number'], 2) action = block['data']['data'][0]['payload']['data']['actions'][0] ppl_r_p = action['payload']['action']['proposal_response_payload'] events_obj = ppl_r_p['extension']['events'] self.assertEqual(events_obj['event_name'], 'invoked') self.assertEqual(events_obj['chaincode_id'], CC_NAME) self.assertEqual(events_obj['payload'], b'400') # test missing block is present data = { 'header': { 'number': 0, 'previous_hash': b'', 'data_hash': b'' }, 'data': {'data': []}, 'metadata': {'metadata': []} } block = self.blocks[len(self.blocks) - 1] self.assertEqual(block, data) def test_in_sequence(self): loop = asyncio.get_event_loop() logger.info("\n\nE2E testing started...") loop.run_until_complete(self.channel_create()) loop.run_until_complete(self.channel_join()) loop.run_until_complete(self.chaincode_install()) self.chaincode_install_fail() loop.run_until_complete(self.chaincode_instantiate()) loop.run_until_complete(self.query_instantiated_chaincodes()) loop.run_until_complete(self.chaincode_invoke()) loop.run_until_complete(self.chaincode_query()) loop.run_until_complete(self.query_installed_chaincodes()) loop.run_until_complete(self.query_channels()) loop.run_until_complete(self.query_info()) loop.run_until_complete(self.query_block_by_txid()) loop.run_until_complete(self.query_block_by_hash()) loop.run_until_complete(self.query_block()) loop.run_until_complete(self.query_transaction()) loop.run_until_complete(self.get_channel_config()) loop.run_until_complete(self.get_filtered_block_events()) loop.run_until_complete(self.get_full_block_events()) logger.info("E2E all test cases done\n\n")
class BaseTestCase(unittest.TestCase): """ Base class for test cases. All test cases can feel free to implement this. """ def setUp(self, wipe_all): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../test/fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) if "LOCAL_DEPLOY" in os.environ: LOCAL_DEPLOY = os.environ["LOCAL_DEPLOY"] == "True" GCP_DEPLOY = not LOCAL_DEPLOY self.channel_tx = \ E2E_CONFIG[NETWORK_NAME]['channel-artifacts']['channel.tx'] self.compose_file_path = \ E2E_CONFIG[NETWORK_NAME]['docker']['compose_file_trustas_gcp'] if GCP_DEPLOY else \ E2E_CONFIG[NETWORK_NAME]['docker']['compose_file_trustas_localhost'] self.config_yaml = \ E2E_CONFIG[NETWORK_NAME]['channel-artifacts']['config_yaml'] self.channel_profile = \ E2E_CONFIG[NETWORK_NAME]['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/trustas_net_gcp.json') if GCP_DEPLOY else \ Client('test/fixtures/network.json') # Client('test/fixtures/local-10peers.json') self.channel_name = "businesschannel" # default application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') global ALIVE ALIVE = True # Boot up the testing network self.start_test_env(wipe_all) return HOST, NAME def tearDown(self, keep_network=False): if not keep_network: self.shutdown_test_env() global ALIVE ALIVE = False # Logs Hyperledger network output def __log_network(self): # capture logs output, _, _ = cli_call( ["docker-compose", "-f", self.compose_file_path, "logs", "-f"]) output = output.decode() # remove color encoding ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') output = ansi_escape.sub('', output) # create output dir if it does not exist mkdir_p('/'.join(LOG_FILE.split('/')[:-1])) # write log with open(LOG_FILE, "w+") as fp: fp.write(output) # Logs Docker network traffic def __network_traffic(self): global ALIVE command = [ "docker", "stats", "--no-stream", "--all", "--format", "{{.Name}},{{.NetIO}}" ] mkdir_p(NET_STATS_DIR) filename = os.path.join(NET_STATS_DIR, str(time.time()) + ".csv") while ALIVE: netstats, _, _ = cli_call(command) netstats = netstats.decode() measurement = str(time.time()) lines = [] for line in netstats.split('\n'): columns = line.split(',') if not line or len(columns) < 2: lines.append('\n') continue # individual, agregado / input, output / peers, orderer # from 3rd column, remove whitespaces and separate ingress and egress traffic val = columns[1].replace(" ", "").split('/') if len(val) < 2: lines.append('\n') continue # convert B, KB, MB, ... into numbers only ingress = human_to_bytes(val[0]) egress = human_to_bytes(val[1]) # join everything to the line line = ','.join([measurement] + columns + [str(ingress), str(egress)]) lines.append(line) netstats = '\n'.join(lines) with open(filename, "a") as f: f.write(netstats) # TODO: ver como timestamp varia com 100 peers time.sleep(1) def start_test_env(self, wipe_all): if wipe_all: print(" > Wiping old assets") # Remove unwanted containers, images, and files cli_call(["./cleanup.sh"]) if "LOCAL_DEPLOY" in os.environ: LOCAL_DEPLOY = os.environ["LOCAL_DEPLOY"] == "True" GCP_DEPLOY = not LOCAL_DEPLOY # GCP environment if GCP_DEPLOY: HOST, _, _ = cli_call([ "curl", "--ssl", "-sH", "Metadata-Flavor: Google", "http://metadata.google.internal/computeMetadata/v1/instance/hostname" ]) NAME, _, _ = cli_call([ "curl", "--ssl", "-sH", "Metadata-Flavor: Google", "http://metadata.google.internal/computeMetadata/v1/instance/name" ]) HOST = HOST.decode() NAME = NAME.decode() os.environ["GCP_HOST"] = HOST os.environ["GCP_NAME"] = NAME service = NAME + ".org1.example.com" if NAME.startswith( "peer") else NAME + ".example.com" print(" > Starting service {}".format(service)) cli_call([ "docker-compose", "-f", self.compose_file_path, "up", "--no-start" ]) cli_call([ "docker-compose", "-f", self.compose_file_path, "start", service ]) # local environment else: host = "localhost" name = "localhost" print(" > Setting network... see it with \"docker stats\"") cli_call([ "docker-compose", "-f", self.compose_file_path, "up", "-d", "--scale", "cli=0" ]) time.sleep(1) network_logs = threading.Thread(target=self.__log_network) network_logs.start() print(" > Logging Network output to \"{}\"".format(LOG_FILE)) network_traffic = threading.Thread(target=self.__network_traffic) network_traffic.start() print(" > Logging Network Traffic".format(LOG_FILE)) def shutdown_test_env(self): print(" > Shutting down network") # Get network down cli_call([ "docker-compose", "-f", self.compose_file_path, "down", "--volumes" ])
class ChannelEventHubTest(unittest.TestCase): def setUp(self): super(ChannelEventHubTest, self).setUp() self.client = Client('test/fixtures/network.json') self.channel_name = "businesschannel" # default application channel self.channel = self.client.new_channel(self.channel_name) self.blocks = [] self.org = 'org1.example.com' self.peer = self.client.get_peer('peer0.' + self.org) self.org_admin = self.client.get_user(self.org, 'Admin') self.loop = asyncio.get_event_loop() def onEvent(self, block): self.blocks.append(block) def test_start_twice(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) channel_event_hub.registerBlockEvent(start=0) with self.assertRaises(Exception) as e: channel_event_hub.connect(start=0) self.assertEqual( 'Not able to connect with start/stop block when a' ' registered listener has those options.', str(e.exception)) def test_start_twice_from_listener(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) s = channel_event_hub.connect(start=0, stop='newest') with self.assertRaises(Exception) as e: channel_event_hub.registerBlockEvent(start=0) try: self.loop.run_until_complete(s) # will fail as no peer is running except Exception: pass channel_event_hub.disconnect() self.assertEqual( 'The registration with a start/stop block must be' ' done before calling connect()', str(e.exception)) def test_registered_before(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) channel_event_hub.registerChaincodeEvent('foo', 'bar') with self.assertRaises(Exception) as e: channel_event_hub.registerBlockEvent(start=0) self.assertEqual( 'Only one event registration is allowed when' ' start/stop block are used.', str(e.exception)) def test_start_bad_connect(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) with self.assertRaises(Exception) as e: channel_event_hub.connect(start='foo') self.assertEqual( 'start value must be: last_seen, oldest, newest or' ' an integer', str(e.exception)) def test_start_bad_listener(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) with self.assertRaises(Exception) as e: channel_event_hub.registerBlockEvent(start='foo') self.assertEqual('start must be an integer', str(e.exception)) def test_stop_bad_listener(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) with self.assertRaises(Exception) as e: channel_event_hub.registerBlockEvent(stop='foo') self.assertEqual('stop must be an integer, newest or sys.maxsize', str(e.exception)) def test_start_greater_connect(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) with self.assertRaises(Exception) as e: channel_event_hub.connect(start=20, stop=10) self.assertEqual('start cannot be greater than stop', str(e.exception)) def test_start_greater_listener(self): channel_event_hub = self.channel.newChannelEventHub( self.peer, self.org_admin) with self.assertRaises(Exception) as e: channel_event_hub.registerBlockEvent(start=20, stop=10) self.assertEqual('start cannot be greater than stop', str(e.exception))
class BaseTestCase(unittest.TestCase): """ Base class for test cases. All test cases can feel free to implement this. """ def setUp(self): self.gopath_bak = os.environ.get('GOPATH', '') gopath = os.path.normpath( os.path.join(os.path.dirname(__file__), "../fixtures/chaincode")) os.environ['GOPATH'] = os.path.abspath(gopath) self.channel_tx = \ NET_CONFIG['channel-artifacts']['channel.tx'] self.compose_file_path = \ NET_CONFIG['docker']['compose_file_tls'] self.config_yaml = \ NET_CONFIG['channel-artifacts']['config_yaml'] self.channel_profile = \ NET_CONFIG['channel-artifacts']['channel_profile'] self.client = Client('test/fixtures/trustas-net.json') self.channel_name = "businesschannel" # application channel self.user = self.client.get_user('org1.example.com', 'Admin') self.assertIsNotNone(self.user, 'org1 admin should not be None') global ALIVE ALIVE = True # Boot up the testing network self.start_test_env() def tearDown(self): time.sleep(1) self.shutdown_test_env() global ALIVE ALIVE = False def check_logs(self): cli_call([ "docker-compose", "-f", self.compose_file_path, "logs", "--tail=200" ]) def start_test_env(self): cli_call(["docker-compose", "-f", self.compose_file_path, "up", "-d"]) time.sleep(1) if FABRIC_LOGS: network_logs = threading.Thread(target=self.__log_network) network_logs.start() print(" > Logging Network output to \"{}\"".format(LOG_FILE)) network_traffic = threading.Thread(target=self.__network_traffic) network_traffic.start() print(" > Logging Network Traffic") def shutdown_test_env(self): cli_call(["docker-compose", "-f", self.compose_file_path, "down"]) # Logs Hyperledger network output def __log_network(self): # capture logs output, _, _ = cli_call( ["docker-compose", "-f", self.compose_file_path, "logs", "-f"]) output = output.decode() # remove color encoding ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') output = ansi_escape.sub('', output) # create output dir if it does not exist mkdir_p('/'.join(LOG_FILE.split('/')[:-1])) # write log with open(LOG_FILE, "w+") as fp: fp.write(output) # Logs Docker network traffic def __network_traffic(self): global ALIVE command = [ "docker", "stats", "--no-stream", "--all", "--format", "{{.Name}},{{.NetIO}}" ] mkdir_p(NET_STATS_DIR) filename = os.path.join(NET_STATS_DIR, str(time.time()) + ".csv") while ALIVE: netstats, _, _ = cli_call(command) netstats = netstats.decode() measurement = str(time.time()) lines = [] for line in netstats.split('\n'): columns = line.split(',') if not line or len(columns) < 2: lines.append('\n') continue # individual, agregado / input, output / peers, orderer # from 3rd column, remove whitespaces and separate ingress and egress traffic val = columns[1].replace(" ", "").split('/') if len(val) < 2: lines.append('\n') continue # convert B, KB, MB, ... into numbers only ingress = human_to_bytes(val[0]) egress = human_to_bytes(val[1]) # join everything to the line line = ','.join([measurement] + columns + [str(ingress), str(egress)]) lines.append(line) netstats = '\n'.join(lines) with open(filename, "a") as f: f.write(netstats)