Browse Source

integration-tests: use Proposal resource lock to simplify full secnario

Mokhtar Naamani 4 years ago
parent
commit
a956a255f0

+ 2 - 2
tests/network-tests/src/Job.ts

@@ -93,11 +93,11 @@ export class Job {
 
     this.debug('Running')
     const flowRunResults = await Promise.allSettled(
-      this._flows.map(async (flow) => {
+      this._flows.map(async (flow, index) => {
         const locker = resources.createLocker()
         try {
           await flow({
-            api: jobProps.apiFactory.getApi(`${this.label}:${flow.name}`),
+            api: jobProps.apiFactory.getApi(`${this.label}:${flow.name}-${index}`),
             env: jobProps.env,
             query: jobProps.query,
             lock: locker.lock,

+ 19 - 15
tests/network-tests/src/Resources.ts

@@ -4,10 +4,10 @@ import Debugger from 'debug'
 
 const debug = Debugger('resources')
 
-export type Resources = Record<ResourceName, Resource>
-export type ResourceLocker = (resource: ResourceName, timeout?: number) => Promise<() => void>
+type NamedLocks = Record<Resource, Lock>
+export type ResourceLocker = (resource: Resource, timeout?: number) => Promise<() => void>
 
-export class Resource {
+class Lock {
   private name: string
 
   // the number of concurrent locks that can be acquired concurrently before the resource
@@ -20,7 +20,7 @@ export class Resource {
     this.concurrency = concurrency || 1
   }
 
-  public async lock(timeoutMinutes = 1): Promise<() => void> {
+  public async lock(timeoutMinutes = 2): Promise<() => void> {
     const timeoutAt = Date.now() + timeoutMinutes * 60 * 1000
 
     while (this.lockCount === this.concurrency) {
@@ -45,31 +45,35 @@ export class Resource {
   }
 }
 
-export enum ResourceName {
+export enum Resource {
   Council = 'Council',
   Proposals = 'Proposals',
 }
 
 export class ResourceManager {
   // Internal Map
-  private resources = new Map<string, Resource>()
+  private resources = new Map<string, Lock>()
 
-  private readonly locks: Resources
+  private readonly locks: NamedLocks
 
   constructor() {
-    this.locks = this.createNamedResources()
+    this.locks = this.createNamedLocks()
   }
 
-  private add(key: string, concurrency?: number): Resource {
+  private add(key: string, concurrency?: number): Lock {
     assert(!this.resources.has(key))
-    this.resources.set(key, new Resource(key, concurrency))
-    return this.resources.get(key) as Resource
+    this.resources.set(key, new Lock(key, concurrency))
+    return this.resources.get(key) as Lock
   }
 
-  private createNamedResources(): Resources {
+  private createNamedLocks(): NamedLocks {
     return {
-      [ResourceName.Council]: this.add(ResourceName.Council),
-      [ResourceName.Proposals]: this.add(ResourceName.Proposals, 5),
+      [Resource.Council]: this.add(Resource.Council),
+      // We assume that a flow will only have one active proposal at a time
+      // Runtime is configured for MaxActiveProposalLimit = 5
+      // So we should ensure we don't exceed that number of active proposals
+      // which limits the number of concurrent tests that create proposals
+      [Resource.Proposals]: this.add(Resource.Proposals, 5),
     }
   }
 
@@ -80,7 +84,7 @@ export class ResourceManager {
     }
     return {
       release,
-      lock: async (resource: ResourceName, timeout?: number) => {
+      lock: async (resource: Resource, timeout?: number) => {
         const unlock = await this.locks[resource].lock(timeout)
         unlockers.push(unlock)
         return unlock

+ 2 - 2
tests/network-tests/src/flows/proposals/councilSetup.ts → tests/network-tests/src/flows/council/setup.ts

@@ -5,7 +5,7 @@ import { ElectCouncilFixture } from '../../fixtures/councilElectionModule'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import Debugger from 'debug'
 import { FixtureRunner } from '../../Fixture'
-import { ResourceName } from '../../Resources'
+import { Resource } from '../../Resources'
 
 export default async function councilSetup({ api, env, lock }: FlowProps): Promise<void> {
   const label = 'councilSetup'
@@ -13,7 +13,7 @@ export default async function councilSetup({ api, env, lock }: FlowProps): Promi
 
   debug('Started')
 
-  await lock(ResourceName.Council)
+  await lock(Resource.Council)
 
   // Skip creating council if already elected
   if ((await api.getCouncil()).length) {

+ 3 - 1
tests/network-tests/src/flows/proposals/electionParametersProposal.ts

@@ -3,11 +3,13 @@ import { ElectionParametersProposalFixture } from '../../fixtures/proposalsModul
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource } from '../../Resources'
 
 // Election parameters proposal scenario
-export default async function electionParametersProposal({ api }: FlowProps): Promise<void> {
+export default async function electionParametersProposal({ api, lock }: FlowProps): Promise<void> {
   const debug = Debugger('flow:electionParametersProposal')
   debug('Started')
+  await lock(Resource.Proposals)
 
   // Pre-Conditions: some members and an elected council
   const council = await api.getCouncil()

+ 9 - 5
tests/network-tests/src/flows/proposals/manageLeaderRole.ts

@@ -20,19 +20,21 @@ import { WorkerId } from '@joystream/types/working-group'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource, ResourceLocker } from '../../Resources'
 
 export default {
-  storage: async function ({ api, env }: FlowProps): Promise<void> {
-    return manageLeaderRole(api, env, WorkingGroups.StorageWorkingGroup)
+  storage: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return manageLeaderRole(api, env, WorkingGroups.StorageWorkingGroup, lock)
   },
-  content: async function ({ api, env }: FlowProps): Promise<void> {
-    return manageLeaderRole(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
+  content: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return manageLeaderRole(api, env, WorkingGroups.ContentDirectoryWorkingGroup, lock)
   },
 }
 
-async function manageLeaderRole(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups) {
+async function manageLeaderRole(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups, lock: ResourceLocker) {
   const debug = Debugger(`flow:managerLeaderRole:${group}`)
   debug('Started')
+  await lock(Resource.Proposals)
 
   const leaderAccount = api.createKeyPairs(1)[0].address
 
@@ -80,6 +82,7 @@ async function manageLeaderRole(api: Api, env: NodeJS.ProcessEnv, group: Working
   )
 
   await new FixtureRunner(voteForCreateOpeningProposalFixture).run()
+
   const openingId = api.findOpeningAddedEvent(voteForCreateOpeningProposalFixture.events, group) as OpeningId
   assert(openingId)
 
@@ -107,6 +110,7 @@ async function manageLeaderRole(api: Api, env: NodeJS.ProcessEnv, group: Working
     api,
     beginWorkingGroupLeaderApplicationReviewFixture.getCreatedProposalId() as ProposalId
   )
+
   await new FixtureRunner(voteForBeginReviewProposal).run()
 
   const fillLeaderOpeningProposalFixture = new FillLeaderOpeningProposalFixture(

+ 3 - 1
tests/network-tests/src/flows/proposals/spendingProposal.ts

@@ -4,10 +4,12 @@ import { SpendingProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource } from '../../Resources'
 
-export default async function spendingProposal({ api, env }: FlowProps): Promise<void> {
+export default async function spendingProposal({ api, env, lock }: FlowProps): Promise<void> {
   const debug = Debugger('flow:spendingProposals')
   debug('Started')
+  await lock(Resource.Proposals)
 
   const spendingBalance: BN = new BN(+env.SPENDING_BALANCE!)
   const mintCapacity: BN = new BN(+env.COUNCIL_MINTING_CAPACITY!)

+ 3 - 1
tests/network-tests/src/flows/proposals/textProposal.ts

@@ -3,10 +3,12 @@ import { TextProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource } from '../../Resources'
 
-export default async function textProposal({ api }: FlowProps): Promise<void> {
+export default async function textProposal({ api, lock }: FlowProps): Promise<void> {
   const debug = Debugger('flow:textProposal')
   debug('Started')
+  await lock(Resource.Proposals)
 
   // Pre-conditions: members and council
   const council = await api.getCouncil()

+ 3 - 1
tests/network-tests/src/flows/proposals/updateRuntime.ts

@@ -6,10 +6,12 @@ import { PaidTermId } from '@joystream/types/members'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource } from '../../Resources'
 
-export default async function updateRuntime({ api, env }: FlowProps): Promise<void> {
+export default async function updateRuntime({ api, env, lock }: FlowProps): Promise<void> {
   const debug = Debugger('flow:updateRuntime')
   debug('Started')
+  await lock(Resource.Proposals)
 
   const paidTerms: PaidTermId = api.createPaidTermId(new BN(+env.MEMBERSHIP_PAID_TERMS!))
   const runtimePath: string = env.RUNTIME_WASM_PATH!

+ 3 - 1
tests/network-tests/src/flows/proposals/validatorCountProposal.ts

@@ -4,10 +4,12 @@ import { ValidatorCountProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource } from '../../Resources'
 
-export default async function validatorCount({ api, env }: FlowProps): Promise<void> {
+export default async function validatorCount({ api, env, lock }: FlowProps): Promise<void> {
   const debug = Debugger('flow:validatorCountProposal')
   debug('Started')
+  await lock(Resource.Proposals)
 
   // Pre-conditions: members and council
   const council = await api.getCouncil()

+ 7 - 5
tests/network-tests/src/flows/proposals/workingGroupMintCapacityProposal.ts

@@ -6,20 +6,22 @@ import { ProposalId } from '@joystream/types/proposals'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource, ResourceLocker } from '../../Resources'
 
 export default {
-  storage: async function ({ api, env }: FlowProps): Promise<void> {
-    return workingGroupMintCapactiy(api, env, WorkingGroups.StorageWorkingGroup)
+  storage: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return workingGroupMintCapactiy(api, env, WorkingGroups.StorageWorkingGroup, lock)
   },
 
-  content: async function ({ api, env }: FlowProps): Promise<void> {
-    return workingGroupMintCapactiy(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
+  content: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return workingGroupMintCapactiy(api, env, WorkingGroups.ContentDirectoryWorkingGroup, lock)
   },
 }
 
-async function workingGroupMintCapactiy(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups) {
+async function workingGroupMintCapactiy(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups, lock: ResourceLocker) {
   const debug = Debugger(`flow:workingGroupMintCapacityProposal:${group}`)
   debug('Started')
+  await lock(Resource.Proposals)
 
   const mintCapacityIncrement: BN = new BN(env.MINT_CAPACITY_INCREMENT!)
 

+ 7 - 5
tests/network-tests/src/flows/workingGroup/workerPayout.ts

@@ -16,19 +16,21 @@ import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
+import { Resource, ResourceLocker } from '../../Resources'
 
 export default {
-  storage: async function ({ api, env }: FlowProps): Promise<void> {
-    return workerPayouts(api, env, WorkingGroups.StorageWorkingGroup)
+  storage: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return workerPayouts(api, env, WorkingGroups.StorageWorkingGroup, lock)
   },
-  content: async function ({ api, env }: FlowProps): Promise<void> {
-    return workerPayouts(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
+  content: async function ({ api, env, lock }: FlowProps): Promise<void> {
+    return workerPayouts(api, env, WorkingGroups.ContentDirectoryWorkingGroup, lock)
   },
 }
 
-async function workerPayouts(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups) {
+async function workerPayouts(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups, lock: ResourceLocker) {
   const debug = Debugger(`flow:workerPayout:${group}`)
   debug('Started')
+  await lock(Resource.Proposals)
 
   const paidTerms: PaidTermId = api.createPaidTermId(new BN(+env.MEMBERSHIP_PAID_TERMS!))
   const applicationStake: BN = new BN(env.WORKING_GROUP_APPLICATION_STAKE!)

+ 9 - 14
tests/network-tests/src/scenarios/full.ts

@@ -1,5 +1,5 @@
 import creatingMemberships from '../flows/membership/creatingMemberships'
-import councilSetup from '../flows/proposals/councilSetup'
+import councilSetup from '../flows/council/setup'
 import leaderSetup from '../flows/workingGroup/leaderSetup'
 import electionParametersProposal from '../flows/proposals/electionParametersProposal'
 import manageLeaderRole from '../flows/proposals/manageLeaderRole'
@@ -18,30 +18,25 @@ scenario(async ({ job }) => {
 
   const councilJob = job('council setup', councilSetup)
 
-  // Runtime is configured for MaxActiveProposalLimit = 5
-  // So we should ensure we don't exceed that number of active proposals
-  // which limits the number of concurrent tests that create proposals
-  const proposalsJob1 = job('proposals 1', [
+  job('proposals', [
     electionParametersProposal,
     spendingProposal,
     textProposal,
     validatorCountProposal,
+    wgMintCapacityProposal.storage,
+    wgMintCapacityProposal.content,
+    manageLeaderRole.storage,
+    manageLeaderRole.content,
   ]).requires(councilJob)
 
-  const proposalsJob2 = job('proposals 2', [wgMintCapacityProposal.storage, wgMintCapacityProposal.content])
-    .requires(councilJob)
-    .after(proposalsJob1)
+  const manageLeadsJob = job('lead-roles', [manageLeaderRole.storage, manageLeaderRole.content]).requires(councilJob)
 
-  const leadRolesJob = job('lead roles', [manageLeaderRole.storage, manageLeaderRole.content])
-    .requires(councilJob)
-    .after(proposalsJob2)
-
-  const leadSetupJob = job('setup leads', [leaderSetup.storage, leaderSetup.content]).after(leadRolesJob)
+  const leadSetupJob = job('setup leads', [leaderSetup.storage, leaderSetup.content]).after(manageLeadsJob)
 
   // Test bug only on one instance of working group is sufficient
   job('at least value bug', atLeastValueBug).requires(leadSetupJob)
 
-  // tests minting payouts (required council to set mint capacity)
+  // tests minting payouts (requires council to set mint capacity)
   job('worker payouts', [workerPayout.storage, workerPayout.content]).requires(leadSetupJob).requires(councilJob)
 
   job('working group tests', [

+ 11 - 0
tests/network-tests/src/scenarios/tests/resource-locks-1.ts

@@ -0,0 +1,11 @@
+import { scenario } from '../../Scenario'
+import { FlowProps } from '../../Flow'
+import { Resource } from '../../Resources'
+
+async function flow1({ lock }: FlowProps) {
+  await lock(Resource.Council)
+}
+
+scenario(async ({ job }) => {
+  job('test', [flow1, flow1])
+})

+ 14 - 0
tests/network-tests/src/scenarios/tests/resource-locks-2.ts

@@ -0,0 +1,14 @@
+import { scenario } from '../../Scenario'
+import { FlowProps } from '../../Flow'
+import { Resource } from '../../Resources'
+
+async function flow({ lock }: FlowProps) {
+  await lock(Resource.Proposals)
+}
+
+scenario(async ({ job }) => {
+  // Runtime is configured for MaxActiveProposalLimit = 5
+  // So we should ensure we don't exceed that number of active proposals
+  // which limits the number of concurrent tests that create proposals
+  job('test', [flow, flow, flow, flow, flow, flow])
+})