From dcbfa5735524e669f420f1be3a071f2583d05c22 Mon Sep 17 00:00:00 2001 From: danielAlvess <48626389+danielAlvess@users.noreply.github.com> Date: Tue, 22 Sep 2020 09:52:39 +0700 Subject: [PATCH] feat/#46 add unit test for position follow (#49) Co-authored-by: Quoc Le --- community/community.wasm | Bin 326323 -> 326301 bytes community/include/community.hpp | 4 +- community/src/community.cpp | 5 +- test/community/community.abi | 33 ---- test/community/community.wasm | Bin 339114 -> 326301 bytes test/position.test.ts | 336 ++++++++++++++++++++++++++++++++ 6 files changed, 341 insertions(+), 37 deletions(-) create mode 100644 test/position.test.ts diff --git a/community/community.wasm b/community/community.wasm index ed093e51114ff51e066a60919dd6c8a05f80cc93..9f1623df5cc568a9a098b3bb89149e20c882ed35 100755 GIT binary patch delta 521 zcmY+9ze@u#7>1KC&E2KHIO$oW1^t?-E`o!#Lo1D-btxTPT|HO3TEW4|sY515!NEaL zEVR8p!MeFQ2(FIZ9Q^KDQ3FS~ zc>DxgqVJ+(SPfRt*=5_phZeL@nQT}EhN=qQiDr8_hRlebPMdRD(9NYNL@}{uY`evP89-Vp{8UI|M=RrM^Ha>3F?J$ z$R&71l9-#QP}cQTDMJ{Ba*htNJcE+1j=W)e3XVA(;!A{ zM_o35EY@sq43(xt*3L0vn0oA9VF{o@Cux-NQ<>k*#Q7>5X_bJJwhwxVv^x`6w_jse z<6KD^X3GW Uvx5khxV*fHfIcz2iBkFIH+Mi{x&QzG delta 510 zcmYk3y-EW?6oqH*=>E(ky6UPSh2EV)qn(A(LLnpg)A-ZrE4X5(tx+s|0E@vQl?WCV z3yJ|Z0bjtpOh~PFR*@_WJ8;hZ&bdr$F!ef^%DzJWc-sr_dLeK3Lb!hk`eOo`{A#p) z`VOn2DbX{m4i)sa*qVr-fuSj-HDKDuum*uD zP%pdk0qe&uia6>_`&1~AB>1i#VbG7lsv;6`f9u30u5grOa=Ar|#)RB)(daFSXIK+O zXZ!g9>5MF_WcJJkWfWae+C~lyF6~VYaUiJMrVcxc$pkj}57`NwLh-^QH3H$v7 zV|KCw(?jY(2NnxqhPKSO9twKnlw`9xK5MfMoXkn|cgvLFnT)%4NSIsVKX#!DI0UBH S#DUe_Ll@|X_Ct4MWb+3~2WnCP diff --git a/community/include/community.hpp b/community/include/community.hpp index 94e24cf..f5b9d8d 100644 --- a/community/include/community.hpp +++ b/community/include/community.hpp @@ -556,7 +556,9 @@ CONTRACT community : public contract ((v1.position)(v1_position)(v1_position_table)) ((v1.codeexec)(v1_sole_decision)(v1_code_sole_decision_table)) ((v1.amenexec)(v1_sole_decision)(v1_amend_sole_decision_table)) - ((v1.cproposal)(v1_code_proposal)(v1_code_proposals_table)) + ((v1.filling)(v1_election_rule)(v1_election_table)) + ((v1.pproposal)(v1_pos_proposal)(v1_posproposal_table)) + ((v1.candidate)(v1_pos_candidate)(v1_poscandidate_table)) ) #endif }; \ No newline at end of file diff --git a/community/src/community.cpp b/community/src/community.cpp index 2873d06..a5d696c 100644 --- a/community/src/community.cpp +++ b/community/src/community.cpp @@ -1264,7 +1264,6 @@ ACTION community::createpos( vector code_actions; code_actions.push_back("configpos"_n); - // TO DO: create configpos with creator (exec_type = SOLE_DESICION) for code_execution_right amendment_execution_right auto configCode = _codes.emplace(ram_payer, [&](auto &row) { row.code_id = _codes.available_primary_key(); row.code_name = PO_Config; @@ -1666,9 +1665,9 @@ ACTION community::voteforpos(name community_account, uint64_t pos_id, name voter check(candidate_itr != _pos_candidate.end(), "ERR::CANDIDATE_NOT_ESIXT::The candidate does not exist"); auto new_voters_detail = candidate_itr->voters; - auto voter_detail_itr = std::find(candidate_itr->voters.begin(), candidate_itr->voters.end(), voter); + auto voter_detail_itr = std::find(new_voters_detail.begin(), new_voters_detail.end(), voter); - if (voter_detail_itr == candidate_itr->voters.end()) + if (voter_detail_itr == new_voters_detail.end()) { if (vote_status == VoteStatus::VOTE) { new_voters_detail.push_back(voter); diff --git a/test/community/community.abi b/test/community/community.abi index 3d657d3..69fc95f 100644 --- a/test/community/community.abi +++ b/test/community/community.abi @@ -403,34 +403,6 @@ } ] }, - { - "name": "hydraload", - "base": "", - "fields": [ - { - "name": "payload", - "type": "hydraload_payload[]" - } - ] - }, - { - "name": "hydraload_payload", - "base": "", - "fields": [ - { - "name": "table_name", - "type": "name" - }, - { - "name": "scope", - "type": "name" - }, - { - "name": "row_data", - "type": "bytes" - } - ] - }, { "name": "initadminpos", "base": "", @@ -1277,11 +1249,6 @@ "type": "execproposal", "ricardian_contract": "" }, - { - "name": "hydraload", - "type": "hydraload", - "ricardian_contract": "" - }, { "name": "initadminpos", "type": "initadminpos", diff --git a/test/community/community.wasm b/test/community/community.wasm index 101ff73737c4261f4e5ff46b738b99708040cb55..9f1623df5cc568a9a098b3bb89149e20c882ed35 100755 GIT binary patch delta 19457 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 { + let blockchain = new Blockchain(config); + let governanceContract; + let communityCreator; + const communityAccountName = 'community1.c'; + let communityAccount; + const positionCandidate1 = blockchain.createAccount('candidate1'); + const positionCandidate2 = blockchain.createAccount('candidate2'); + const positionVoter1 = blockchain.createAccount('posvoter1'); + const positionVoter2 = blockchain.createAccount('posvoter2'); + const positionVoter3 = blockchain.createAccount('posvoter3'); + + let newCreatedPositionId; + + beforeAll(async () => { + const initAccount = await initGovernanceContract(blockchain, communityAccountName); + governanceContract = initAccount.governanceContract; + communityCreator = initAccount.communityCreator; + communityAccount = initAccount.communityAccount; + }); + + beforeEach(async () => { + // governanceContract.resetTables(); + }); + + it("should create new position", async () => { + // add account to community member + const codeTable = await governanceContract.getTableRowsScoped('v1.code')[communityAccount.accountName]; + const createPositionCode = codeTable.find(code => code.code_name === 'po.create'); + + const inputActionData = { + community_account: communityAccount.accountName, + creator: communityCreator.accountName, + pos_name: 'test position', + max_holder: 9, + filled_through: FillingType.ELECTION, + term: 1, + next_term_start_at: 949363200, + voting_period: 2591999, + right_candidate: { + is_anyone: false, + is_any_community_member: false, + required_badges: [], + required_positions: [], + required_tokens: [], + required_exp: 0, + accounts: [positionCandidate1.accountName, positionCandidate2.accountName], + }, + right_voter: { + is_anyone: false, + is_any_community_member: false, + required_badges: [], + required_positions: [], + required_tokens: [], + required_exp: 0, + accounts: [positionVoter1.accountName, positionVoter2.accountName, positionVoter3.accountName], + }, + }; + + const serializeActionData = '8040f0d94d2d2545003256f9d26cd4450d7465737420706f736974696f6e09000000000000000101000000000000000022963800000000ff8c2700000000000000000000000000000000000002004050d92497a641008050d92497a64100000000000000000000000000030000085765ba31ad0000105765ba31ad0000185765ba31ad'; + await governanceContract.contract.execcode({ + community_account: communityAccount.accountName, + exec_account: communityCreator.accountName, + code_id: createPositionCode.code_id, + code_actions: [{ + code_action: 'createpos', + packed_params: serializeActionData, + }], + }, [{ + actor: communityCreator.accountName, + permission: 'active', + }]); + + const positions = governanceContract.getTableRowsScoped( + `v1.position` + )[communityAccount.accountName]; + + + const newCreatedPosition = positions.find(p => p.pos_name === inputActionData.pos_name); + + expect(newCreatedPosition).toBeTruthy(); + expect(newCreatedPosition.pos_name).toBe(inputActionData.pos_name); + expect(+newCreatedPosition.max_holder).toBe(inputActionData.max_holder); + expect(+newCreatedPosition.fulfillment_type).toBe(inputActionData.filled_through); + + newCreatedPositionId = newCreatedPosition.pos_id; + + const fillingRuleTable = governanceContract.getTableRowsScoped( + `v1.filling` + )[communityAccount.accountName]; + + const newPositionFillingRule = fillingRuleTable.find(f => f.pos_id === newCreatedPositionId); + + expect(newPositionFillingRule).toBeTruthy(); + expect(+newPositionFillingRule.term).toBe(inputActionData.term); + expect(newPositionFillingRule.next_term_start_at).toBe((new Date(inputActionData.next_term_start_at * 1000)).toISOString().substring(0, 23)); + expect(+newPositionFillingRule.voting_period).toBe(inputActionData.voting_period); + expect(newPositionFillingRule.pos_candidates.accounts).toEqual(inputActionData.right_candidate.accounts); + expect(newPositionFillingRule.pos_voters.accounts).toEqual(inputActionData.right_voter.accounts); + }); + + it('should init code of position when create position', async () => { + const positions = governanceContract.getTableRowsScoped( + `v1.position` + )[communityAccount.accountName]; + + const codeTable = governanceContract.getTableRowsScoped( + `v1.code` + )[communityAccount.accountName]; + + const newCreatedPosition = positions.find(p => p.pos_id === newCreatedPositionId); + + const configPositionCodeId = newCreatedPosition.refer_codes.find(r => r.key === 'po.config'); + const appointPositionCodeId = newCreatedPosition.refer_codes.find(r => r.key === 'po.appoint'); + const dismissPositionCodeId = newCreatedPosition.refer_codes.find(r => r.key === 'po.dismiss'); + + const configPositionCode = codeTable.find(c => c.code_id === configPositionCodeId.value); + expect(configPositionCode).toBeTruthy(); + expect(configPositionCode.code_name).toBe('po.config'); + expect(configPositionCode.code_actions).toEqual(['configpos']); + expect(configPositionCode.contract_name).toEqual(governanceContract.accountName); + expect(configPositionCode.code_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(configPositionCode.amendment_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(configPositionCode.code_type.type).toEqual(CodeTypeEnum.POSITION_CONFIG); + expect(configPositionCode.code_type.refer_id).toEqual(newCreatedPositionId); + + const appointPositionCode = codeTable.find(c => c.code_id === appointPositionCodeId.value); + expect(appointPositionCode).toBeTruthy(); + expect(appointPositionCode.code_name).toBe('po.appoint'); + expect(appointPositionCode.code_actions).toEqual(['appointpos']); + expect(appointPositionCode.contract_name).toEqual(governanceContract.accountName); + expect(appointPositionCode.code_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(appointPositionCode.amendment_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(appointPositionCode.code_type.type).toEqual(CodeTypeEnum.POSITION_APPOINT); + expect(appointPositionCode.code_type.refer_id).toEqual(newCreatedPositionId); + + const dismissPositionCode = codeTable.find(c => c.code_id === dismissPositionCodeId.value); + expect(dismissPositionCode).toBeTruthy(); + expect(dismissPositionCode.code_name).toBe('po.dismiss'); + expect(dismissPositionCode.code_actions).toEqual(['dismisspos']); + expect(dismissPositionCode.contract_name).toEqual(governanceContract.accountName); + expect(dismissPositionCode.code_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(dismissPositionCode.amendment_exec_type).toEqual(ExecutionType.SOLE_DECISION); + expect(dismissPositionCode.code_type.type).toEqual(CodeTypeEnum.POSITION_DISMISS); + expect(dismissPositionCode.code_type.refer_id).toEqual(newCreatedPositionId); + }); + + it('should nominate for position', async () => { + const testingNominationPositionId = 999; + const positionProposalId = '1'; + await governanceContract.loadFixtures(`v1.position`, { + 'community1.c': [{ + pos_id: testingNominationPositionId, + pos_name: 'test vote', + max_holder: 1, + holders: [], + fulfillment_type: FillingType.ELECTION, + refer_codes: [ + { + key: 'po.config', + value: 16 + }, + { + key: 'po.appoint', + value: 17 + }, + { + key: 'po.dismiss', + value: 18 + }, + ] + }] + }); + await governanceContract.loadFixtures(`v1.filling`, { + 'community1.c': [{ + pos_id: testingNominationPositionId, + term: 1, + next_term_start_at: '2000-01-02T00:00:01', + voting_period: 172804, + pos_candidates: { + is_anyone: false, + is_any_community_member: false, + required_badges: [], + required_positions: [], + required_tokens: [], + required_exp: 0, + accounts: [positionCandidate1.accountName, positionCandidate2.accountName], + }, + pos_voters: { + is_anyone: false, + is_any_community_member: false, + required_badges: [], + required_positions: [], + required_tokens: [], + required_exp: 0, + accounts: [positionVoter1.accountName, positionVoter2.accountName, positionVoter3.accountName], + }, + }] + }); + + await governanceContract.loadFixtures(`v1.pproposal`, { + 'community1.c': [{ + pos_id: testingNominationPositionId, + pos_proposal_id: positionProposalId, + pos_proposal_status: ProposalStatus.IN_PROGRESS, + approved_at: '1970-01-01T00:00:00' + }] + }); + + await governanceContract.contract.nominatepos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + owner: positionCandidate1.accountName + },[{ + actor: positionCandidate1.accountName, + permission: 'active', + }]); + + await governanceContract.contract.nominatepos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + owner: positionCandidate2.accountName + },[{ + actor: positionCandidate2.accountName, + permission: 'active', + }]); + + const positionCandidateTable = governanceContract.getTableRowsScoped( + `v1.candidate` + )[positionProposalId.padStart(13, '.')]; + + const newCandidate1 = positionCandidateTable.find(c => c.cadidate === positionCandidate1.accountName); + + expect(newCandidate1).toBeTruthy(); + expect(newCandidate1.cadidate).toBe(positionCandidate1.accountName); + expect(newCandidate1.voters.length).toBe(0); + + const newCandidate2 = positionCandidateTable.find(c => c.cadidate === positionCandidate2.accountName); + + expect(newCandidate2).toBeTruthy(); + expect(newCandidate2.cadidate).toBe(positionCandidate2.accountName); + expect(newCandidate2.voters.length).toBe(0); + }); + + it('should vote for position candidate', async () => { + const testingNominationPositionId = 999; + const positionProposalId = '1'; + // voter1 vote for candidate1; + await governanceContract.contract.voteforpos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + voter: positionVoter1.accountName, + candidate: positionCandidate1.accountName, + vote_status: 1, + },[{ + actor: positionVoter1.accountName, + permission: 'active', + }]); + + let positionCandidateTable = governanceContract.getTableRowsScoped( + `v1.candidate` + )[positionProposalId.padStart(13, '.')]; + + let candidate1 = positionCandidateTable.find(c => c.cadidate === positionCandidate1.accountName); + + expect(candidate1.cadidate).toBe(positionCandidate1.accountName); + expect(candidate1.voters).toEqual([positionVoter1.accountName]); + + // voter2 vote for candidate1; + await governanceContract.contract.voteforpos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + voter: positionVoter2.accountName, + candidate: positionCandidate1.accountName, + vote_status: 1, + },[{ + actor: positionVoter2.accountName, + permission: 'active', + }]); + + positionCandidateTable = governanceContract.getTableRowsScoped( + `v1.candidate` + )[positionProposalId.padStart(13, '.')]; + + candidate1 = positionCandidateTable.find(c => c.cadidate === positionCandidate1.accountName); + + expect(candidate1.cadidate).toBe(positionCandidate1.accountName); + expect(candidate1.voters).toEqual([positionVoter1.accountName, positionVoter2.accountName]); + }); + + it('should reject the position candidate', async () => { + const testingNominationPositionId = 999; + const positionProposalId = '1'; + // voter1 vote for candidate1; + await governanceContract.contract.voteforpos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + voter: positionVoter1.accountName, + candidate: positionCandidate1.accountName, + vote_status: 0, + },[{ + actor: positionVoter1.accountName, + permission: 'active', + }]); + + let positionCandidateTable = governanceContract.getTableRowsScoped( + `v1.candidate` + )[positionProposalId.padStart(13, '.')]; + + let candidate1 = positionCandidateTable.find(c => c.cadidate === positionCandidate1.accountName); + + expect(candidate1.cadidate).toBe(positionCandidate1.accountName); + expect(candidate1.voters).not.toContain([positionVoter1.accountName]); + }); + + it('should throw error if vote for position candidate that is not exist', async () => { + const testingNominationPositionId = 999; + // voter1 vote for not exist candidate; + await expect(governanceContract.contract.voteforpos({ + community_account: communityAccount.accountName, + pos_id: testingNominationPositionId, + voter: positionVoter1.accountName, + candidate: 'notexistcan', + vote_status: 1, + },[{ + actor: positionVoter1.accountName, + permission: 'active', + }])).rejects.toThrowError('ERR::CANDIDATE_NOT_ESIXT::The candidate does not exist'); + }); +});