Browse Source

integration-tests: factour out Flow, Job, FlowManager

Mokhtar Naamani 4 years ago
parent
commit
c6bd9dedf3
26 changed files with 206 additions and 197 deletions
  1. 5 6
      tests/network-tests/src/Api.ts
  2. 4 10
      tests/network-tests/src/Fixture.ts
  3. 5 0
      tests/network-tests/src/Flow.ts
  4. 40 0
      tests/network-tests/src/FlowManager.ts
  5. 124 0
      tests/network-tests/src/Job.ts
  6. 3 161
      tests/network-tests/src/Scenario.ts
  7. 1 1
      tests/network-tests/src/flows/contentDirectory/contentDirectoryInitialization.ts
  8. 1 1
      tests/network-tests/src/flows/contentDirectory/creatingChannel.ts
  9. 1 1
      tests/network-tests/src/flows/contentDirectory/creatingVideo.ts
  10. 1 1
      tests/network-tests/src/flows/contentDirectory/updatingChannel.ts
  11. 1 1
      tests/network-tests/src/flows/membership/creatingMemberships.ts
  12. 1 1
      tests/network-tests/src/flows/proposals/councilSetup.ts
  13. 1 1
      tests/network-tests/src/flows/proposals/electionParametersProposal.ts
  14. 1 1
      tests/network-tests/src/flows/proposals/manageLeaderRole.ts
  15. 1 1
      tests/network-tests/src/flows/proposals/spendingProposal.ts
  16. 1 1
      tests/network-tests/src/flows/proposals/textProposal.ts
  17. 1 1
      tests/network-tests/src/flows/proposals/updateRuntime.ts
  18. 1 1
      tests/network-tests/src/flows/proposals/validatorCountProposal.ts
  19. 1 1
      tests/network-tests/src/flows/proposals/workingGroupMintCapacityProposal.ts
  20. 1 1
      tests/network-tests/src/flows/storageNode/getContentFromStorageNode.ts
  21. 1 1
      tests/network-tests/src/flows/workingGroup/atLeastValueBug.ts
  22. 1 1
      tests/network-tests/src/flows/workingGroup/leaderSetup.ts
  23. 1 1
      tests/network-tests/src/flows/workingGroup/manageWorkerAsLead.ts
  24. 1 1
      tests/network-tests/src/flows/workingGroup/manageWorkerAsWorker.ts
  25. 1 1
      tests/network-tests/src/flows/workingGroup/workerPayout.ts
  26. 6 1
      tests/network-tests/src/sender.ts

+ 5 - 6
tests/network-tests/src/Api.ts

@@ -45,11 +45,11 @@ export enum WorkingGroups {
 }
 
 export class Api {
-  protected readonly api: ApiPromise
-  protected readonly sender: Sender
-  protected readonly keyring: Keyring
+  private readonly api: ApiPromise
+  private readonly sender: Sender
+  private readonly keyring: Keyring
   // source of funds for all new accounts
-  protected readonly treasuryAccount: string
+  private readonly treasuryAccount: string
 
   public static async create(provider: WsProvider, treasuryAccountUri: string, sudoAccountUri: string): Promise<Api> {
     let connectAttempts = 0
@@ -79,8 +79,7 @@ export class Api {
   constructor(api: ApiPromise, treasuryAccountUri: string, sudoAccountUri: string) {
     this.api = api
     this.keyring = new Keyring({ type: 'sr25519' })
-    const treasuryKey = this.keyring.addFromUri(treasuryAccountUri)
-    this.treasuryAccount = treasuryKey.address
+    this.treasuryAccount = this.keyring.addFromUri(treasuryAccountUri).address
     this.keyring.addFromUri(sudoAccountUri)
     this.sender = new Sender(api, this.keyring)
   }

+ 4 - 10
tests/network-tests/src/Fixture.ts

@@ -102,15 +102,9 @@ export class FixtureRunner {
 
     // TODO: record starting block
 
-    try {
-      await this.fixture.runner()
-      // TODO: record ending block
-      const err = this.fixture.executionError()
-      assert.equal(err, undefined)
-    } catch (err) {
-      // This should make tracking which fixture caused the exception easier
-      console.log(err)
-      throw err
-    }
+    await this.fixture.runner()
+    // TODO: record ending block
+    const err = this.fixture.executionError()
+    assert.equal(err, undefined)
   }
 }

+ 5 - 0
tests/network-tests/src/Flow.ts

@@ -0,0 +1,5 @@
+import { Api } from './Api'
+import { QueryNodeApi } from './QueryNodeApi'
+
+export type FlowArgs = { api: Api; env: NodeJS.ProcessEnv; query: QueryNodeApi }
+export type Flow = (args: FlowArgs) => Promise<void>

+ 40 - 0
tests/network-tests/src/FlowManager.ts

@@ -0,0 +1,40 @@
+import { EventEmitter } from 'events'
+import { Flow, FlowArgs } from './Flow'
+import { Job, JobOutcome } from './Job'
+
+export class FlowManager extends EventEmitter {
+  private readonly flowArgs: FlowArgs
+  private _jobs: Job[] = []
+
+  constructor(flowArgs: FlowArgs) {
+    super()
+    this.flowArgs = flowArgs
+  }
+
+  public createJob(label: string, flows: Flow[] | Flow): Job {
+    const arrFlows: Array<Flow> = []
+    const job = new Job(this, arrFlows.concat(flows), label)
+
+    this._jobs.push(job)
+
+    return job
+  }
+
+  public async run(): Promise<void> {
+    this.emit('run', this.flowArgs)
+
+    const outcomes = await Promise.all(this._jobs.map((job) => job.outcome))
+
+    // summary of job results
+    console.error('Job Results:')
+    outcomes.forEach((outcome, i) => {
+      const { label } = this._jobs[i]
+      console.error(`${label}: ${outcome}`)
+    })
+
+    const failed = outcomes.find((outcome) => outcome !== JobOutcome.Succeeded)
+    if (failed) {
+      throw new Error('Scenario Failed')
+    }
+  }
+}

+ 124 - 0
tests/network-tests/src/Job.ts

@@ -0,0 +1,124 @@
+import Debugger from 'debug'
+import { EventEmitter } from 'events'
+
+import { Flow, FlowArgs } from './Flow'
+
+function noop() {
+  // No-Op
+}
+
+class InvertedPromise<T> {
+  public resolve: (value: T) => void = noop
+  public reject: (reason?: any) => void = noop
+  public readonly promise: Promise<T>
+
+  constructor() {
+    this.promise = new Promise((resolve, reject) => {
+      this.resolve = resolve
+      this.reject = reject
+    })
+  }
+}
+
+export enum JobOutcome {
+  Succeeded = 'Succeeded',
+  Failed = 'Failed',
+  Skipped = 'Skipped',
+}
+
+export class Job {
+  private _required: Job[] = []
+  private _after: Job[] = []
+  private _locked = false
+  private readonly _flows: Flow[]
+  private readonly _manager: EventEmitter
+  private readonly _outcome: InvertedPromise<JobOutcome>
+  private readonly _label: string
+  private readonly debug: Debugger.Debugger
+
+  constructor(manager: EventEmitter, flows: Flow[], label: string) {
+    this._label = label
+    this._manager = manager
+    this._flows = flows
+    this._outcome = new InvertedPromise<JobOutcome>()
+    this._manager.on('run', this.run.bind(this))
+    this.debug = Debugger(`job:${this._label}`)
+  }
+
+  // Depend on another job to complete successfully
+  public requires(job: Job): Job {
+    if (this._locked) throw new Error('Job is locked')
+    if (job === this) throw new Error('Job Cannot depend on itself')
+    if (job.hasDependencyOn(this)) {
+      throw new Error('Job Circualr dependency')
+    }
+    this._required.push(job)
+    return this
+  }
+
+  // Depend on another job to complete (does not matter if it is successful)
+  public after(job: Job): Job {
+    if (this._locked) throw new Error('Job is locked')
+    if (job === this) throw new Error('Job Cannot depend on itself')
+    if (job.hasDependencyOn(this)) {
+      throw new Error('Job Circualr dependency')
+    }
+    this._after.push(job)
+    return this
+  }
+
+  public then(job: Job): Job {
+    job.requires(this)
+    return job
+  }
+
+  public hasDependencyOn(job: Job): boolean {
+    return !!this._required.find((j) => j === job) || !!this._after.find((j) => j === job)
+  }
+
+  // configure to have flows run serially instead of in parallel
+  // public serially(): Job {
+  //   return this
+  // }
+
+  get outcome(): Promise<JobOutcome> {
+    return this._outcome.promise
+  }
+
+  get label(): string {
+    return this._label
+  }
+
+  private async run(flowArgs: FlowArgs): Promise<void> {
+    // prevent any additional changes to configuration
+    this._locked = true
+
+    // wait for all required dependencies to complete successfully
+    const requiredOutcomes = await Promise.all(this._required.map((job) => job.outcome))
+    if (requiredOutcomes.find((outcome) => outcome !== JobOutcome.Succeeded)) {
+      this.debug('[Skipping] - Required jobs not successful!')
+      return this._outcome.resolve(JobOutcome.Skipped)
+    }
+
+    // Wait for other jobs to complete, irrespective of outcome
+    await Promise.all(this._after.map((job) => job.outcome))
+
+    this.debug('Running')
+    const flowRunResults = await Promise.allSettled(this._flows.map((flow) => flow(flowArgs)))
+
+    flowRunResults.forEach((result, ix) => {
+      if (result.status === 'rejected') {
+        this.debug(`flow ${ix} failed:`)
+        console.error(result.reason)
+      }
+    })
+
+    if (flowRunResults.find((result) => result.status === 'rejected')) {
+      this.debug('[Failed]')
+      this._outcome.resolve(JobOutcome.Failed)
+    } else {
+      this.debug('[Succeeded]')
+      this._outcome.resolve(JobOutcome.Succeeded)
+    }
+  }
+}

+ 3 - 161
tests/network-tests/src/Scenario.ts

@@ -4,167 +4,9 @@ import { QueryNodeApi } from './QueryNodeApi'
 import { config } from 'dotenv'
 import { ApolloClient, InMemoryCache } from '@apollo/client'
 import Debugger from 'debug'
-import { EventEmitter } from 'events'
-
-function noop() {
-  // No-Op
-}
-
-class InvertedPromise<T> {
-  public resolve: (value: T) => void = noop
-  public reject: (reason?: any) => void = noop
-  public readonly promise: Promise<T>
-
-  constructor() {
-    this.promise = new Promise((resolve, reject) => {
-      this.resolve = resolve
-      this.reject = reject
-    })
-  }
-}
-
-export type FlowArgs = { api: Api; env: NodeJS.ProcessEnv; query: QueryNodeApi }
-export type Flow = (args: FlowArgs) => Promise<void>
-
-enum JobOutcome {
-  Succeeded = 'Succeeded',
-  Failed = 'Failed',
-  Skipped = 'Skipped',
-}
-
-class Job {
-  private _required: Job[] = []
-  private _after: Job[] = []
-  private _locked = false
-  private readonly _flows: Flow[]
-  private readonly _manager: FlowManager
-  private readonly _outcome: InvertedPromise<JobOutcome>
-  private readonly _label: string
-  private readonly debug: Debugger.Debugger
-
-  constructor(manager: FlowManager, flows: Flow[], label: string) {
-    this._label = label
-    this._manager = manager
-    this._flows = flows
-    this._outcome = new InvertedPromise<JobOutcome>()
-    this._manager.on('run', this.run.bind(this))
-    this.debug = Debugger(`job:${this._label}`)
-  }
-
-  // Depend on another job to complete successfully
-  public requires(job: Job): Job {
-    if (this._locked) throw new Error('Job is locked')
-    if (job === this) throw new Error('Job Cannot depend on itself')
-    if (job.hasDependencyOn(this)) {
-      throw new Error('Job Circualr dependency')
-    }
-    this._required.push(job)
-    return this
-  }
-
-  // Depend on another job to complete (does not matter if it is successful)
-  public after(job: Job): Job {
-    if (this._locked) throw new Error('Job is locked')
-    if (job === this) throw new Error('Job Cannot depend on itself')
-    if (job.hasDependencyOn(this)) {
-      throw new Error('Job Circualr dependency')
-    }
-    this._after.push(job)
-    return this
-  }
-
-  public then(job: Job): Job {
-    job.requires(this)
-    return job
-  }
-
-  public hasDependencyOn(job: Job): boolean {
-    return !!this._required.find((j) => j === job) || !!this._after.find((j) => j === job)
-  }
-
-  // configure to have flows run serially instead of in parallel
-  // public serially(): Job {
-  //   return this
-  // }
-
-  get outcome(): Promise<JobOutcome> {
-    return this._outcome.promise
-  }
-
-  get label(): string {
-    return this._label
-  }
-
-  private async run(flowArgs: FlowArgs): Promise<void> {
-    // prevent any additional changes to configuration
-    this._locked = true
-
-    // wait for all required dependencies to complete successfully
-    const requiredOutcomes = await Promise.all(this._required.map((job) => job.outcome))
-    if (requiredOutcomes.find((outcome) => outcome !== JobOutcome.Succeeded)) {
-      this.debug('[Skipping] - Required jobs not successful!')
-      return this._outcome.resolve(JobOutcome.Skipped)
-    }
-
-    // Wait for other jobs to complete, irrespective of outcome
-    await Promise.all(this._after.map((job) => job.outcome))
-
-    this.debug('Running')
-    const flowRunResults = await Promise.allSettled(this._flows.map((flow) => flow(flowArgs)))
-
-    flowRunResults.forEach((result, ix) => {
-      if (result.status === 'rejected') {
-        this.debug(`flow ${ix} failed:`)
-        console.error(result.reason)
-      }
-    })
-
-    if (flowRunResults.find((result) => result.status === 'rejected')) {
-      this.debug('[Failed]')
-      this._outcome.resolve(JobOutcome.Failed)
-    } else {
-      this.debug('[Succeeded]')
-      this._outcome.resolve(JobOutcome.Succeeded)
-    }
-  }
-}
-
-class FlowManager extends EventEmitter {
-  private readonly flowArgs: FlowArgs
-  private _jobs: Job[] = []
-
-  constructor(flowArgs: FlowArgs) {
-    super()
-    this.flowArgs = flowArgs
-  }
-
-  public createJob(label: string, flows: Flow[] | Flow): Job {
-    const arrFlows: Array<Flow> = []
-    const job = new Job(this, arrFlows.concat(flows), label)
-
-    this._jobs.push(job)
-
-    return job
-  }
-
-  public async run(): Promise<void> {
-    this.emit('run', this.flowArgs)
-
-    const outcomes = await Promise.all(this._jobs.map((job) => job.outcome))
-
-    // summary of job results
-    console.error('Job Results:')
-    outcomes.forEach((outcome, i) => {
-      const { label } = this._jobs[i]
-      console.error(`${label}: ${outcome}`)
-    })
-
-    const failed = outcomes.find((outcome) => outcome !== JobOutcome.Succeeded)
-    if (failed) {
-      throw new Error('Scenario Failed')
-    }
-  }
-}
+import { Flow } from './Flow'
+import { Job } from './Job'
+import { FlowManager } from './FlowManager'
 
 export async function scenario(
   fn: (cfg: {

+ 1 - 1
tests/network-tests/src/flows/contentDirectory/contentDirectoryInitialization.ts

@@ -1,4 +1,4 @@
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import Debugger from 'debug'
 const debug = Debugger('initializeContentDirectory')
 

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

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { Utils } from '../../utils'
 import { CreateChannelFixture } from '../../fixtures/contentDirectoryModule'
 import { ChannelEntity } from '@joystream/cd-schemas/types/entities/ChannelEntity'

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

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { CreateVideoFixture } from '../../fixtures/contentDirectoryModule'
 import { VideoEntity } from '@joystream/cd-schemas/types/entities/VideoEntity'
 import { assert } from 'chai'

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

@@ -1,5 +1,5 @@
 import { Api } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { UpdateChannelFixture } from '../../fixtures/contentDirectoryModule'
 import { ChannelEntity } from '@joystream/cd-schemas/types/entities/ChannelEntity'
 import { assert } from 'chai'

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

@@ -1,4 +1,4 @@
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import {
   BuyMembershipHappyCaseFixture,
   BuyMembershipWithInsufficienFundsFixture,

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

@@ -1,6 +1,6 @@
 import BN from 'bn.js'
 import { PaidTermId } from '@joystream/types/members'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { ElectCouncilFixture } from '../../fixtures/councilElectionModule'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import Debugger from 'debug'

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

@@ -1,4 +1,4 @@
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { ElectionParametersProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'

+ 1 - 1
tests/network-tests/src/flows/proposals/manageLeaderRole.ts

@@ -1,6 +1,6 @@
 import BN from 'bn.js'
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import {
   BeginWorkingGroupLeaderApplicationReviewFixture,

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

@@ -1,5 +1,5 @@
 import BN from 'bn.js'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { SpendingProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'

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

@@ -1,4 +1,4 @@
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { TextProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'

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

@@ -1,5 +1,5 @@
 import BN from 'bn.js'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { BuyMembershipHappyCaseFixture } from '../../fixtures/membershipModule'
 import { UpdateRuntimeFixture } from '../../fixtures/proposalsModule'
 import { PaidTermId } from '@joystream/types/members'

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

@@ -1,5 +1,5 @@
 import BN from 'bn.js'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { ValidatorCountProposalFixture } from '../../fixtures/proposalsModule'
 import { assert } from 'chai'
 import { FixtureRunner } from '../../Fixture'

+ 1 - 1
tests/network-tests/src/flows/proposals/workingGroupMintCapacityProposal.ts

@@ -1,6 +1,6 @@
 import BN from 'bn.js'
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { VoteForProposalFixture, WorkingGroupMintCapacityProposalFixture } from '../../fixtures/proposalsModule'
 import { ProposalId } from '@joystream/types/proposals'
 import { assert } from 'chai'

+ 1 - 1
tests/network-tests/src/flows/storageNode/getContentFromStorageNode.ts

@@ -3,7 +3,7 @@ import { assert } from 'chai'
 import { ContentId } from '@joystream/types/media'
 import { registry } from '@joystream/types'
 
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { Utils } from '../../utils'
 import Debugger from 'debug'
 

+ 1 - 1
tests/network-tests/src/flows/workingGroup/atLeastValueBug.ts

@@ -1,5 +1,5 @@
 import { WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import { AddWorkerOpeningFixture } from '../../fixtures/workingGroupModule'
 import BN from 'bn.js'
 import { assert } from 'chai'

+ 1 - 1
tests/network-tests/src/flows/workingGroup/leaderSetup.ts

@@ -1,5 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import BN from 'bn.js'
 import { PaidTermId } from '@joystream/types/members'
 import { SudoHireLeadFixture } from '../../fixtures/sudoHireLead'

+ 1 - 1
tests/network-tests/src/flows/workingGroup/manageWorkerAsLead.ts

@@ -1,5 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import {
   ApplyForOpeningFixture,
   AddWorkerOpeningFixture,

+ 1 - 1
tests/network-tests/src/flows/workingGroup/manageWorkerAsWorker.ts

@@ -1,5 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import {
   AddWorkerOpeningFixture,
   ApplyForOpeningFixture,

+ 1 - 1
tests/network-tests/src/flows/workingGroup/workerPayout.ts

@@ -1,5 +1,5 @@
 import { Api, WorkingGroups } from '../../Api'
-import { FlowArgs } from '../../Scenario'
+import { FlowArgs } from '../../Flow'
 import {
   AddWorkerOpeningFixture,
   ApplyForOpeningFixture,

+ 6 - 1
tests/network-tests/src/sender.ts

@@ -112,7 +112,12 @@ export class Sender {
       const nonce = await this.api.rpc.system.accountNextIndex(senderKeyPair.address)
       const signedTx = tx.sign(senderKeyPair, { nonce })
       sentTx = signedTx.toHuman()
-      await signedTx.send(handleEvents)
+      try {
+        await signedTx.send(handleEvents)
+      } catch (err) {
+        this.debug('Submitting Tx failed:', sentTx)
+        throw err
+      }
     })
 
     return whenFinalized