Ver código fonte

integration-tests: scenarion flowmanager WIP

Mokhtar Naamani 4 anos atrás
pai
commit
61be82222b

+ 76 - 2
tests/network-tests/src/Scenario.ts

@@ -5,8 +5,77 @@ import { config } from 'dotenv'
 import { ApolloClient, InMemoryCache } from '@apollo/client'
 import Debugger from 'debug'
 
+export type FlowArgs = { api: Api; env: NodeJS.ProcessEnv; query: QueryNodeApi }
+export type Flow = (args: FlowArgs) => Promise<void>
+
+class Job {
+  private dependencies: Job[]
+  private flowArgs: FlowArgs
+  private flows: Flow[]
+  private manager: FlowManager
+
+  constructor(manager: FlowManager, flowArgs: FlowArgs, flows: Flow[]) {
+    this.manager = manager
+    this.flowArgs = flowArgs
+    this.flows = flows
+  }
+
+  // Depend on another job to complete
+  public afterSuccessOf(job: Job): Job {
+    this.dependencies.push(job)
+    return this
+  }
+
+  // Depend on another job to complete
+  public afterSuccessOrFailureOf(job: Job): Job {
+    this.dependencies.push(job)
+    return this
+  }
+
+  // Allows job to fail (one or more flows failing) without interrupting the scenario
+  // The scenario will still result in failure, but allows other jobs and flows to be tested
+  public allowFailure(): Job {
+    return this
+  }
+
+  // configure to have flows run serially instead of in parallel
+  public serially(): Job {
+    return this
+  }
+}
+
+class FlowManager {
+  private readonly flowArgs: FlowArgs
+  private pendingJobs: Job[]
+  private completedJobs: Job[]
+
+  constructor(flowArgs: FlowArgs) {
+    this.flowArgs = flowArgs
+  }
+
+  public createJob(flows: Flow[]): Job {
+    const job = new Job(this, this.flowArgs, flows)
+
+    this.pendingJobs.push(job)
+
+    // TODO: return a limited interface only for configuring job before it runs
+    return job
+  }
+
+  // Run the jobs in parallel where possible, followed by their dependents
+  public async run(): Promise<void> {
+    
+  }
+}
+
 export async function scenario(
-  fn: (cfg: { api: Api; query: QueryNodeApi; env: NodeJS.ProcessEnv; debug: Debugger.Debugger }) => Promise<void>
+  fn: (cfg: {
+    api: Api
+    query: QueryNodeApi
+    env: NodeJS.ProcessEnv
+    debug: Debugger.Debugger
+    job: (flows: Flow[]) => Job
+  }) => Promise<void>
 ): Promise<void> {
   // Load env variables
   config()
@@ -30,7 +99,12 @@ export async function scenario(
 
   const debug = Debugger('scenario')
 
-  await fn({ api, query, env, debug })
+  const flowManager = new FlowManager({ api, query, env })
+
+  // Does the scenario really need the flow args?
+  await fn({ api, query, env, debug, job: flowManager.createJob.bind(flowManager) })
+
+  await flowManager.run()
 
   // Note: disconnecting and then reconnecting to the chain in the same process
   // doesn't seem to work!

+ 2 - 2
tests/network-tests/src/flows/contentDirectory/creatingChannel.ts

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { QueryNodeApi } from '../../QueryNodeApi'
+import { FlowArgs } from '../../Scenario'
 import { Utils } from '../../utils'
 import { CreateChannelFixture } from '../../fixtures/contentDirectoryModule'
 import { ChannelEntity } from '@joystream/cd-schemas/types/entities/ChannelEntity'
@@ -30,7 +30,7 @@ function assertChannelMatchQueriedResult(queriedChannel: any, channel: ChannelEn
   assert.equal(queriedChannel.isPublic, channel.isPublic, 'Should be equal')
 }
 
-export default async function channelCreation(api: Api, query: QueryNodeApi): Promise<void> {
+export default async function channelCreation({ api, query }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:creatingChannel')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/contentDirectory/creatingVideo.ts

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { QueryNodeApi } from '../../QueryNodeApi'
+import { FlowArgs } from '../../Scenario'
 import { CreateVideoFixture } from '../../fixtures/contentDirectoryModule'
 import { VideoEntity } from '@joystream/cd-schemas/types/entities/VideoEntity'
 import { assert } from 'chai'
@@ -55,7 +55,7 @@ function assertVideoMatchQueriedResult(queriedVideo: any, video: VideoEntity) {
   assert.equal(queriedVideo.isPublic, video.isPublic, 'Should be equal')
 }
 
-export default async function createVideo(api: Api, query: QueryNodeApi): Promise<void> {
+export default async function createVideo({ api, query }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:creatingVideo')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/contentDirectory/updatingChannel.ts

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { QueryNodeApi } from '../../QueryNodeApi'
+import { FlowArgs } from '../../Scenario'
 import { UpdateChannelFixture } from '../../fixtures/contentDirectoryModule'
 import { ChannelEntity } from '@joystream/cd-schemas/types/entities/ChannelEntity'
 import { assert } from 'chai'
@@ -18,7 +18,7 @@ export function createUpdateChannelHandleFixture(api: Api, handle: string, descr
   return new UpdateChannelFixture(api, channelUpdateInput, uniquePropVal)
 }
 
-export default async function updateChannel(api: Api, query: QueryNodeApi): Promise<void> {
+export default async function updateChannel({ api, query }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:updateChannel')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/membership/creatingMemberships.ts

@@ -1,4 +1,4 @@
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import {
   BuyMembershipHappyCaseFixture,
   BuyMembershipWithInsufficienFundsFixture,
@@ -9,7 +9,7 @@ import Debugger from 'debug'
 import { FixtureRunner } from '../../Fixture'
 import { assert } from 'chai'
 
-export default async function membershipCreation(api: Api, env: NodeJS.ProcessEnv): Promise<void> {
+export default async function membershipCreation({ api, env }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:memberships')
   debug('Started')
 

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

@@ -1,12 +1,12 @@
 import BN from 'bn.js'
 import { PaidTermId } from '@joystream/types/members'
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { ElectCouncilFixture } from '../../fixtures/councilElectionModule'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import Debugger from 'debug'
 import { FixtureRunner } from '../../Fixture'
 
-export default async function councilSetup(api: Api, env: NodeJS.ProcessEnv): Promise<void> {
+export default async function councilSetup({ api, env }: FlowArgs): Promise<void> {
   const label = 'councilSetup'
   const debug = Debugger(`flow:${label}`)
 

+ 2 - 2
tests/network-tests/src/flows/proposals/electionParametersProposal.ts

@@ -1,11 +1,11 @@
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { ElectionParametersProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 // Election parameters proposal scenario
-export default async function electionParametersProposal(api: Api, env: NodeJS.ProcessEnv) {
+export default async function electionParametersProposal({ api }: FlowArgs): Promise<void> {
   const debug = Debugger('electionParametersProposal')
   debug('Started')
 

+ 3 - 2
tests/network-tests/src/flows/proposals/manageLeaderRole.ts

@@ -1,5 +1,6 @@
 import BN from 'bn.js'
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import {
   BeginWorkingGroupLeaderApplicationReviewFixture,
@@ -21,10 +22,10 @@ import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageLeaderRole(api, env, WorkingGroups.StorageWorkingGroup)
   },
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageLeaderRole(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }

+ 2 - 2
tests/network-tests/src/flows/proposals/spendingProposal.ts

@@ -1,11 +1,11 @@
 import BN from 'bn.js'
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { SpendingProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
-export default async function spendingProposal(api: Api, env: NodeJS.ProcessEnv) {
+export default async function spendingProposal({ api, env }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:spendingProposals')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/proposals/textProposal.ts

@@ -1,10 +1,10 @@
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { TextProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
-export default async function textProposal(api: Api, env: NodeJS.ProcessEnv) {
+export default async function textProposal({ api }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:textProposal')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/proposals/updateRuntime.ts

@@ -1,5 +1,5 @@
 import BN from 'bn.js'
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import { UpdateRuntimeFixture } from '../../fixtures/proposalsModule'
 import { PaidTermId } from '@joystream/types/members'
@@ -7,7 +7,7 @@ import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
-export default async function updateRuntime(api: Api, env: NodeJS.ProcessEnv) {
+export default async function updateRuntime({ api, env }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:updateRuntime')
   debug('Started')
 

+ 2 - 2
tests/network-tests/src/flows/proposals/validatorCountProposal.ts

@@ -1,11 +1,11 @@
 import BN from 'bn.js'
-import { Api } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { ValidatorCountProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
-export default async function validatorCount(api: Api, env: NodeJS.ProcessEnv) {
+export default async function validatorCount({ api, env }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:validatorCountProposal')
   debug('Started')
 

+ 3 - 2
tests/network-tests/src/flows/proposals/workingGroupMintCapacityProposal.ts

@@ -1,5 +1,6 @@
 import BN from 'bn.js'
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { VoteForProposalFixture, WorkingGroupMintCapacityProposalFixture } from '../../fixtures/proposalsModule'
 import { ProposalId } from '@joystream/types/proposals'
 import { assert } from 'chai'
@@ -7,11 +8,11 @@ import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return workingGroupMintCapactiy(api, env, WorkingGroups.StorageWorkingGroup)
   },
 
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return workingGroupMintCapactiy(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }

+ 2 - 3
tests/network-tests/src/flows/storageNode/getContentFromStorageNode.ts

@@ -3,12 +3,11 @@ import { assert } from 'chai'
 import { ContentId } from '@joystream/types/media'
 import { registry } from '@joystream/types'
 
-import { Api } from '../../Api'
-import { QueryNodeApi } from '../../QueryNodeApi'
+import { FlowArgs } from '../../Scenario'
 import { Utils } from '../../utils'
 import Debugger from 'debug'
 
-export default async function getContentFromStorageNode(api: Api, query: QueryNodeApi): Promise<void> {
+export default async function getContentFromStorageNode({ api, query }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:getContentFromStorageNode')
   debug('Started')
 

+ 3 - 2
tests/network-tests/src/flows/workingGroup/atLeastValueBug.ts

@@ -1,4 +1,5 @@
-import { Api, WorkingGroups } from '../../Api'
+import { WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import { AddWorkerOpeningFixture } from '../../fixtures/workingGroupModule'
 import BN from 'bn.js'
 import { assert } from 'chai'
@@ -6,7 +7,7 @@ import Debugger from 'debug'
 import { FixtureRunner } from '../../Fixture'
 
 // Zero at least value bug scenario
-export default async function zeroAtLeastValueBug(api: Api, env: NodeJS.ProcessEnv) {
+export default async function zeroAtLeastValueBug({ api, env }: FlowArgs): Promise<void> {
   const debug = Debugger('flow:atLeastValueBug')
   debug('Started')
   const applicationStake: BN = new BN(env.WORKING_GROUP_APPLICATION_STAKE!)

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

@@ -1,23 +1,24 @@
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import BN from 'bn.js'
 import { PaidTermId } from '@joystream/types/members'
 import { SudoHireLeadFixture } from '../../fixtures/sudoHireLead'
 import { assert } from 'chai'
-import { KeyringPair } from '@polkadot/keyring/types'
+// import { KeyringPair } from '@polkadot/keyring/types'
 import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return leaderSetup(api, env, WorkingGroups.StorageWorkingGroup)
   },
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return leaderSetup(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }
 
 // Worker application happy case scenario
-async function leaderSetup(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups): Promise<KeyringPair> {
+async function leaderSetup(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroups): Promise<void> {
   const debug = Debugger(`flow:leaderSetup:${group}`)
   debug('Started')
 
@@ -53,5 +54,6 @@ async function leaderSetup(api: Api, env: NodeJS.ProcessEnv, group: WorkingGroup
 
   debug('Done')
 
-  return leadKeyPair
+  // Who ever needs it will need to get it from the Api layer
+  // return leadKeyPair
 }

+ 3 - 2
tests/network-tests/src/flows/workingGroup/manageWorkerAsLead.ts

@@ -1,4 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import {
   ApplyForOpeningFixture,
   AddWorkerOpeningFixture,
@@ -16,10 +17,10 @@ import Debugger from 'debug'
 import { FixtureRunner } from '../../Fixture'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageWorkerAsLead(api, env, WorkingGroups.StorageWorkingGroup)
   },
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageWorkerAsLead(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }

+ 3 - 2
tests/network-tests/src/flows/workingGroup/manageWorkerAsWorker.ts

@@ -1,4 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import {
   AddWorkerOpeningFixture,
   ApplyForOpeningFixture,
@@ -15,10 +16,10 @@ import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageWorkerAsWorker(api, env, WorkingGroups.StorageWorkingGroup)
   },
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return manageWorkerAsWorker(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }

+ 3 - 2
tests/network-tests/src/flows/workingGroup/workerPayout.ts

@@ -1,4 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
+import { FlowArgs } from '../../Scenario'
 import {
   AddWorkerOpeningFixture,
   ApplyForOpeningFixture,
@@ -17,10 +18,10 @@ import { FixtureRunner } from '../../Fixture'
 import Debugger from 'debug'
 
 export default {
-  storage: async function (api: Api, env: NodeJS.ProcessEnv) {
+  storage: async function ({ api, env }: FlowArgs): Promise<void> {
     return workerPayouts(api, env, WorkingGroups.StorageWorkingGroup)
   },
-  content: async function (api: Api, env: NodeJS.ProcessEnv) {
+  content: async function ({ api, env }: FlowArgs): Promise<void> {
     return workerPayouts(api, env, WorkingGroups.ContentDirectoryWorkingGroup)
   },
 }

+ 33 - 29
tests/network-tests/src/scenarios/full.ts

@@ -13,41 +13,45 @@ import manageWorkerAsWorker from '../flows/workingGroup/manageWorkerAsWorker'
 import workerPayout from '../flows/workingGroup/workerPayout'
 import { scenario } from '../Scenario'
 
-scenario(async ({ api, env, debug }) => {
+scenario(async ({ api, debug, job }) => {
   debug('Enabling failed tx logs')
   api.enableTxLogs()
 
-  await Promise.all([creatingMemberships(api, env), councilSetup(api, env)])
+  job([creatingMemberships])
+
+  const councilJob = job([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
-  await Promise.all([
-    electionParametersProposal(api, env),
-    spendingProposal(api, env),
-    textProposal(api, env),
-    validatorCountProposal(api, env),
-  ])
-
-  await Promise.all([
-    wgMintCapacityProposal.storage(api, env),
-    wgMintCapacityProposal.content(api, env),
-    manageLeaderRole.storage(api, env),
-    manageLeaderRole.content(api, env),
-  ])
-
-  await Promise.all([leaderSetup.storage(api, env), leaderSetup.content(api, env)])
-
-  // All tests below require an active Lead for each group
+  const proposalsJob1 = job([
+    electionParametersProposal,
+    spendingProposal,
+    textProposal,
+    validatorCountProposal,
+  ]).afterSuccessOf(councilJob)
+
+  job([wgMintCapacityProposal.storage, wgMintCapacityProposal.content])
+    .afterSuccessOf(councilJob)
+    .afterSuccessOf(proposalsJob1)
+
+  const leadRolesJob = job([manageLeaderRole.storage, manageLeaderRole.content])
+    .afterSuccessOf(councilJob)
+    .afterSuccessOf(proposalsJob1)
+
+  const leadSetupJob = job([leaderSetup.storage, leaderSetup.content]).afterSuccessOf(leadRolesJob)
+
+  /* All tests below require an active Lead for each group */
+
   // Test bug only on one instance of working group is sufficient
-  await atLeastValueBug(api, env)
-
-  await Promise.all([
-    manageWorkerAsLead.storage(api, env),
-    manageWorkerAsWorker.storage(api, env),
-    workerPayout.storage(api, env),
-    manageWorkerAsLead.content(api, env),
-    manageWorkerAsWorker.content(api, env),
-    workerPayout.content(api, env),
-  ])
+  job([atLeastValueBug]).afterSuccessOf(leadSetupJob)
+
+  job([
+    manageWorkerAsLead.storage,
+    manageWorkerAsWorker.storage,
+    workerPayout.storage,
+    manageWorkerAsLead.content,
+    manageWorkerAsWorker.content,
+    workerPayout.content,
+  ]).afterSuccessOf(leadSetupJob)
 })