text:
const express = require('express')
const app = express()
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
const middleware = require('../../../src/middleware/middleware')
app.use(middleware.createCtxAndReqUUID)

const nonExistentCveId = 'CVE-2017-35437'
const errors = require('../../../src/controller/cve-id.controller/error')
const error = new errors.CveIdControllerError()

const cveIdFixtures = require('./mockObjects.cve-id')
const cveIdController = require('../../../src/controller/cve-id.controller/cve-id.controller')
const cveIdParams = require('../../../src/controller/cve-id.controller/cve-id.middleware')

class NullUserRepo {
  async getUserUUID () {
    return null
  }

  async findOneByUserNameAndOrgUUID () {
    return null
  }

  async isAdmin () {
    return null
  }
}

class NullCveRepo {
  async findOneByCveId () {
    return null
  }
}

class UserModifyCveIdOrgAndStateModified {
  async getUserUUID () {
    return cveIdFixtures.secretariatUser.UUID
  }
}

class OrgModifyCveIdOrgAndStateModified {
  async getOrgUUID () {
    return cveIdFixtures.org.UUID
  }

  async findOneByShortName (shortName) {
    return cveIdFixtures.org
  }
}

class CveIdModifyCveIdOrgAndStateModified {
  constructor () {
    this.testRes1 = JSON.parse(JSON.stringify(cveIdFixtures.cveRejected))
    this.testRes1.owning_cna = cveIdFixtures.org.short_name
    this.testRes1.requested_by.cna = cveIdFixtures.owningOrg.short_name
    this.testRes1.requested_by.user = cveIdFixtures.owningOrgUser.username
  }

  async findOneByCveId () {
    return cveIdFixtures.cveReserved
  }

  async findOneAndUpdate () {
    return null
  }

  async aggregate () {
    return [this.testRes1]
  }

  // Returns count less than quota for testing
  async countDocuments (uuid, state) {
    return 200
  }
}

describe('Testing the PUT /cve-id/:id endpoint in CveId Controller', () => {
  context('Negative Tests', () => {
    it('CVE ID does not exist', (done) => {
      class CveIdModifyCveIdDoesntExist {
        async findOneByCveId () {
          return null
        }

        // Returns count less than quota for testing
        async countDocuments (uuid, state) {
          return 200
        }
      }

      class OrgModifyCveIdDoesntExist {
        async getOrgUUID () {
          return null
        }

        async findOneByShortName (shortName) {
          return cveIdFixtures.org
        }
      }

      app.route('/cve-id-modify-secretariat-cve-id-doesnt-exist/:id')
        .put((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdModifyCveIdDoesntExist() },
            getOrgRepository: () => { return new OrgModifyCveIdDoesntExist() },
            getUserRepository: () => { return new NullUserRepo() },
            getCveRepository: () => { return new NullCveRepo() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_UPDATE_SINGLE)

      chai.request(app)
        .put(`/cve-id-modify-secretariat-cve-id-doesnt-exist/${nonExistentCveId}`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(404)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.cveIdNotFound(nonExistentCveId)
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Org query parameter is provided but new org does not exist', (done) => {
      class OrgModifyCveIdOrgDoesntExist {
        async getOrgUUID () {
          return null
        }

        async findOneByShortName (shortName) {
          return cveIdFixtures.org
        }
      }

      app.route('/cve-id-modify-org-doesnt-exist/:id')
        .put((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdModifyCveIdOrgAndStateModified() },
            getOrgRepository: () => { return new OrgModifyCveIdOrgDoesntExist() },
            getUserRepository: () => { return new NullUserRepo() },
            getCveRepository: () => { return new NullCveRepo() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_UPDATE_SINGLE)

      chai.request(app)
        .put(`/cve-id-modify-org-doesnt-exist/${cveIdFixtures.cveId}?org=${cveIdFixtures.nonExistentOrg.short_name}`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(404)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.orgDne(cveIdFixtures.nonExistentOrg.short_name, 'org', 'query')
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })
    /**
     * For v2.1, CNAs will be able to move a CVE ID back to reserved.
     * But they will not be able to change it to PUBLISHED. This should only be done by
     * submitting a CNA container to POST /cve/:id/cna. So this test should flip to asserting
     * a CVE ID cannot be changed to PUBLISHED once that code is complete.
     */
    // it('State query parameter is provided but state is RESERVED', (done) => {
    //   app.route('/cve-id-modify-state-query-is-reserved/:id')
    //     .put((req, res, next) => {
    //       const factory = {
    //         getCveIdRepository: () => { return new CveIdModifyCveIdOrgAndStateModified() },
    //         getOrgRepository: () => { return new NullOrgRepo() },
    //         getUserRepository: () => { return new NullUserRepo() },
    //         getCveRepository: () => { return new NullCveRepo() }
    //       }
    //       req.ctx.repositories = factory
    //       next()
    //     }, cveIdParams.parsePostParams, cveIdController.CVEID_UPDATE_SINGLE)

    //   chai.request(app)
    //     .put(`/cve-id-modify-state-query-is-reserved/${cveIdFixtures.cveId}?state=RESERVED`)
    //     .set(cveIdFixtures.secretariatHeader)
    //     .end((err, res) => {
    //       if (err) {
    //         done(err)
    //       }

    //       expect(res).to.have.status(400)
    //       expect(res).to.have.property('body').and.to.be.a('object')
    //       const errObj = error.invalidReservedState()
    //       expect(res.body.error).to.equal(errObj.error)
    //       expect(res.body.message).to.equal(errObj.message)
    //       done()
    //     })
    // })
  })

  context('Positive Tests', () => {
    it('Cve is reassigned to another org and state is modified', (done) => {
      app.route('/cve-id-modify-org-and-state-modified/:id')
        .put((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdModifyCveIdOrgAndStateModified() },
            getOrgRepository: () => { return new OrgModifyCveIdOrgAndStateModified() },
            getUserRepository: () => { return new UserModifyCveIdOrgAndStateModified() },
            getCveRepository: () => { return new NullCveRepo() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_UPDATE_SINGLE)

      chai.request(app)
        .put(`/cve-id-modify-org-and-state-modified/${cveIdFixtures.cveId}?state=REJECTED&org=${cveIdFixtures.org.short_name}`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('message').and.to.be.a('string')
          expect(res.body.message).to.equal(cveIdFixtures.cveId + ' was successfully updated.')
          expect(res.body).to.have.property('updated').and.to.be.a('object')
          expect(res.body.updated).to.have.property('state').and.to.equal('REJECTED')
          expect(res.body.updated).to.have.property('owning_cna').and.to.equal(cveIdFixtures.org.short_name)
          expect(res.body.updated).to.have.nested.property('requested_by.cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
          expect(res.body.updated).to.have.nested.property('requested_by.user').and.to.equal(cveIdFixtures.owningOrgUser.username)
          done()
        })
    })

    it('No query parameters are provided', (done) => {
      class CveIdModifyCveIdNoQuery {
        constructor () {
          this.testRes1 = JSON.parse(JSON.stringify(cveIdFixtures.cveRejected))
          this.testRes1.owning_cna = cveIdFixtures.org.short_name
          this.testRes1.requested_by.cna = cveIdFixtures.owningOrg.short_name
          this.testRes1.requested_by.user = cveIdFixtures.owningOrgUser.username
        }

        async findOneByCveId () {
          return this.testRes1
        }

        async findOneAndUpdate () {
          return null
        }

        async aggregate () {
          return [this.testRes1]
        }

        // Returns count less than quota for testing
        async countDocuments (uuid, state) {
          return 200
        }
      }

      app.route('/cve-id-modify-no-query/:id')
        .put((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdModifyCveIdNoQuery() },
            getOrgRepository: () => { return new OrgModifyCveIdOrgAndStateModified() },
            getUserRepository: () => { return new UserModifyCveIdOrgAndStateModified() },
            getCveRepository: () => { return new NullCveRepo() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_UPDATE_SINGLE)

      chai.request(app)
        .put(`/cve-id-modify-no-query/${cveIdFixtures.cveId}`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('message').and.to.be.a('string')
          expect(res.body.message).to.equal(cveIdFixtures.cveId + ' was successfully updated.')
          expect(res.body).to.have.property('updated').and.to.be.a('object')
          expect(res.body.updated).to.have.property('state').and.to.equal('REJECTED')
          expect(res.body.updated).to.have.property('owning_cna').and.to.equal(cveIdFixtures.org.short_name)
          expect(res.body.updated).to.have.nested.property('requested_by.cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
          expect(res.body.updated).to.have.nested.property('requested_by.user').and.to.equal(cveIdFixtures.owningOrgUser.username)
          done()
        })
    })
  })
})


text:
const chai = require('chai')
const expect = chai.expect

const getConstants = require('../../../src/constants').getConstants

// #789 - don't allow lowercase CVE
describe('CVE IDs should be well formed', () => {
  context('Negative tests', () => {
    it('should not match lowercase', () => {
      expect('cve-2022-1234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it('should not match invalid prefix', () => {
      expect('abc-2022-1234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it('should not match non-digit year', () => {
      expect('CVE-abcd-1234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it('should not match non-digit ID', () => {
      expect('CVE-2022-abcdefghij').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it("should not match years that aren't exactly 4 digits", () => {
      expect('CVE-22-1234567890').to.not.match(getConstants().CVE_ID_REGEX)
      expect('CVE-20222-1234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it("should not match IDs that aren't 4-19 digits", () => {
      expect('CVE-2022-123').to.not.match(getConstants().CVE_ID_REGEX)
      expect('CVE-2022-12345678901234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
    it('should not match without dashes', () => {
      expect('CVE20221234567890').to.not.match(getConstants().CVE_ID_REGEX)
    })
  })

  context('Positive tests', () => {
    it('should match uppercase', () => {
      expect('CVE-2022-1234567890').to.match(getConstants().CVE_ID_REGEX)
    })
    it('should match IDs that are 4-19 digits', () => {
      const cveId = 'CVE-2022-'

      // build strings for the ID part
      for (let i = 4; i < 20; i++) {
        // pad the end with a random number up to i
        const fullId = cveId.padEnd(cveId.length + i, Math.floor(Math.random() * 9))
        expect(fullId).to.match(getConstants().CVE_ID_REGEX, `Failed with ${fullId}`)
      }
    })
  })
})

repo_name: CVEProject/cve-services

repo_language: JavaScript

file_name: Dockerfile

mime_type: text/plain


text:
const getConstants = require('../../../src/constants').getConstants
const CONSTANTS = getConstants()
const cveIdYear = '2017'
const cveId = `CVE-${cveIdYear}-4024`

const secretariatHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'mitre',
  'CVE-API-USER': 'cpadro',
  'CVE-API-KEY': 'S96E4QT-SMT4YE3-KX03X6K-4615CED'
}

const owningOrgHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'cisco',
  'CVE-API-USER': 'alopez',
  'CVE-API-KEY': 'SVXPHM9-1VXM0A8-QMG8WN0-29MASSE'
}

const orgHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'siemens',
  'CVE-API-USER': 'rgonz',
  'CVE-API-KEY': '006YPCK-14R46D6-KR24W1K-PJG5BVP'
}

const secretariatOrg = {
  UUID: '15fd129f-af00-4d8c-8f7b-e19b0587223f',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA, CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT]
  },
  name: 'The MITRE Corporation',
  policies: {
    id_quota: 1000
  },
  short_name: 'mitre',
  inUse: false
}

const secretariatUser = {
  UUID: 'e13186d5-ce3d-4fd9-aecd-8698c26897f2',
  org_UUID: secretariatOrg.UUID,
  name: {
    first: 'Cristina',
    last: 'Padro'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$+qGHEfH5h4/tk404iWBxFw$xV96/b4NvQVvlZIq57wTS8s7gfKzsfMXRiOyf3ffgcw',
  username: 'cpadro',
  active: true
}

const owningOrg = {
  UUID: '88c02595-c8f7-4864-a0e7-e09b3e1da691',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA]
  },
  name: 'Cisco',
  policies: {
    id_quota: 1000
  },
  short_name: 'cisco',
  inUse: false
}

const owningOrgUser = {
  UUID: '1fcbf829-81ae-4b53-a61d-9fa04711447f',
  org_UUID: owningOrg.UUID,
  name: {
    first: 'Armando',
    last: 'Lopez',
    middle: 'Jose'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$bHTrVB/WVMI+yscYe1Y1aQ$RdQkx9w9sME6z5W/2tyHu/6WcYGvi1JeY3KLbr+ioBg',
  username: 'alopez',
  active: true
}

const org = {
  UUID: 'c0a1d017-faa5-4608-92ff-5c938da17eff',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA]
  },
  name: 'Siemens',
  policies: {
    id_quota: 500
  },
  short_name: 'siemens',
  inUse: false
}

const orgUser = {
  UUID: '4121968f-cc2d-4680-b9b0-39e98a2182f6',
  owningOrg: org.UUID,
  name: {
    first: 'Rebecca',
    last: 'Gonzalez',
    middle: 'Andrea'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$xADSBGahsOCJfJNGTMMviA$UtHmBfxsw5C6BeKpi7elbxKinDl1FnWZ+i5NdoOb02g',
  username: 'rgonz',
  active: true
}

const nonExistentOrg = {
  UUID: '794715e2-ded9-4a16-8dfd-9a062a63e1d5',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA]
  },
  name: 'The Oval Office',
  policies: {
    id_quota: 5
  },
  short_name: 'oval',
  inUse: false
}

const cveReserved = {
  _id: 1,
  cve_id: cveId,
  cve_year: cveIdYear,
  state: CONSTANTS.CVE_STATES.RESERVED,
  owning_cna: owningOrg.UUID,
  requested_by: {
    cna: owningOrgUser.org_UUID,
    user: owningOrgUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveRejected = {
  _id: 1,
  cve_id: cveId,
  cve_year: cveIdYear,
  state: CONSTANTS.CVE_STATES.REJECTED,
  owning_cna: owningOrg.UUID,
  requested_by: {
    cna: owningOrgUser.org_UUID,
    user: owningOrgUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cvePublished = {
  _id: 1,
  cve_id: cveId,
  cve_year: cveIdYear,
  state: CONSTANTS.CVE_STATES.PUBLISHED,
  owning_cna: owningOrg.UUID,
  requested_by: {
    cna: owningOrgUser.org_UUID,
    user: owningOrgUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveDummy1 = {
  _id: 1,
  cve_id: 'CVE-2019-5012',
  cve_year: '2019',
  state: CONSTANTS.CVE_STATES.RESERVED,
  owning_cna: owningOrg.UUID,
  requested_by: {
    cna: secretariatUser.org_UUID,
    user: secretariatUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveDummy2 = {
  _id: 1,
  cve_id: 'CVE-2018-5111',
  cve_year: '2018',
  state: CONSTANTS.CVE_STATES.REJECTED,
  owning_cna: secretariatOrg.UUID,
  requested_by: {
    cna: secretariatUser.org_UUID,
    user: secretariatUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveDummy3 = {
  _id: 1,
  cve_id: 'CVE-2020-2004',
  cve_year: '2020',
  state: CONSTANTS.CVE_STATES.PUBLISHED,
  owning_cna: secretariatOrg.UUID,
  requested_by: {
    cna: secretariatUser.org_UUID,
    user: secretariatUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveDummy4 = {
  _id: 1,
  cve_id: 'CVE-2020-20026',
  cve_year: '2020',
  state: CONSTANTS.CVE_STATES.PUBLISHED,
  owning_cna: org.UUID,
  requested_by: {
    cna: secretariatUser.org_UUID,
    user: secretariatUser.UUID
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

const cveDummy5 = {
  _id: 1,
  cve_id: 'CVE-2020-20030',
  cve_year: '2020',
  state: CONSTANTS.CVE_STATES.AVAILABLE,
  owning_cna: 'N/A',
  requested_by: {
    cna: 'N/A',
    user: 'N/A'
  },
  time: {
    modified: '2012-03-04T12:34:56.789Z'
  }
}

module.exports = {
  secretariatHeader,
  owningOrgHeader,
  orgHeader,
  secretariatOrg,
  secretariatUser,
  owningOrg,
  owningOrgUser,
  org,
  orgUser,
  nonExistentOrg,
  cveReserved,
  cveRejected,
  cvePublished,
  cveDummy1,
  cveDummy2,
  cveDummy3,
  cveDummy4,
  cveDummy5,
  cveIdYear,
  cveId
}


text:
const chai = require('chai')
const sinon = require('sinon')
const { faker } = require('@faker-js/faker')
const expect = chai.expect
const _ = require('lodash')

const cveIdController = require('../../../src/controller/cve-id.controller/cve-id.controller.js')
const OrgRepository = require('../../../src/repositories/orgRepository.js')
const CveIdRepository = require('../../../src/repositories/cveIdRepository.js')
const UserRepository = require('../../../src/repositories/userRepository.js')

const orgUUID = faker.datatype.uuid()
const orgUUID2 = faker.datatype.uuid()
const userUUID = faker.datatype.uuid()

const stubOrg = {
  short_name: 'testOrg',
  name: 'test_org',
  UUID: orgUUID,
  authority: {
    active_roles: [
      'CNA',
      'Secretariat'
    ]
  }
}

const stubOrg2 = {
  short_name: 'testOrg2',
  name: 'test_org2',
  UUID: orgUUID2,
  authority: {
    active_roles: [
      'CNA'
    ]
  }
}

const stubUser = {
  username: 'testUser',
  org_UUID: orgUUID,
  UUID: userUUID
}

const stubCveId = {
  requested_by: {
    cna: orgUUID,
    user: userUUID
  },
  cve_id: 'CVE-2017-4024',
  cve_year: '2017',
  state: 'PUBLISHED',
  owning_cna: orgUUID2,
  reserved: '2023-05-17T16:57:35.698Z'
}

const builtQuery = {
  cve_year: 1999,
  state: 'RESERVED',
  'time.modified': {
    $gt: '2022-01-07T00:00:00.000Z',
    $lt: '2023-01-07T00:00:00.000Z'
  }
}
describe('Testing getFilteredCveId function', () => {
  let sandbox, status, json, res, next, getOrgRepository,
    orgRepo, getCveIdRepository, cveIdRepo,
    getUserRepository, userRepo, req, cveIdCopy

  // Stub out functions called in insertAdp and reset them for each test
  beforeEach(() => {
    sandbox = sinon.createSandbox()
    status = sandbox.stub()
    json = sandbox.spy()
    res = { json, status }
    next = sandbox.spy()
    status.returns(res)
    cveIdCopy = _.cloneDeep(stubCveId)

    const aggPagResp = {
      itemsList: [cveIdCopy],
      itemCount: 1,
      itemsPerPage: 1000,
      currentPage: 1,
      pageCount: 1,
      pagingCounter: 1,
      hasPrevPage: false,
      hasNextPage: false,
      prevPage: null,
      nextPage: null
    }

    orgRepo = new OrgRepository()
    getOrgRepository = sandbox.stub()
    getOrgRepository.returns(orgRepo)

    userRepo = new UserRepository()
    getUserRepository = sandbox.stub()
    getUserRepository.returns(userRepo)

    cveIdRepo = new CveIdRepository()
    getCveIdRepository = sandbox.stub()
    getCveIdRepository.returns(cveIdRepo)

    sandbox.stub(cveIdRepo, 'findOneByCveId').returns(cveIdCopy)
    sandbox.stub(cveIdRepo, 'aggregatePaginate').returns(aggPagResp)

    sandbox.stub(orgRepo, 'getOrgUUID').returns(stubOrg.UUID)
    sandbox.stub(orgRepo, 'isSecretariat').returns(true)
    sandbox.stub(orgRepo, 'isBulkDownload').returns(false)
    sandbox.stub(orgRepo, 'getAllOrgs').returns([stubOrg, stubOrg2])

    sandbox.stub(userRepo, 'getUserUUID').returns(stubUser.UUID)
    sandbox.stub(userRepo, 'getAllUsers').returns([stubUser])

    sandbox.spy(cveIdController, 'CVEID_GET_FILTER')

    req = {
      ctx: {
        org: stubOrg.short_name,
        uuid: stubOrg.UUID,
        query: {
          cve_id_year: 1999,
          'time_modified.gt': '2022-01-07T00:00:00.000Z',
          'time_modified.lt': '2023-01-07T00:00:00.000Z',
          state: 'RESERVED'
        },
        repositories: {
          getOrgRepository,
          getUserRepository,
          getCveIdRepository
        }
      }
    }
  })

  afterEach(() => {
    sandbox.restore()
  })
  it('Should have correctly built query', async () => {
    await cveIdController.CVEID_GET_FILTER(req, res, next)
    expect(cveIdRepo.aggregatePaginate.calledOnce)
    expect(cveIdRepo.aggregatePaginate.args[0][0][0].$match).to.deep.equal(builtQuery)
  })

  it('Should swap UUIDs for names in Cve-ids', async () => {
    await cveIdController.CVEID_GET_FILTER(req, res, next)
    expect(res.status.args[0][0]).to.equal(200)
    expect(res.json.args[0][0].cve_ids[0].owning_cna).to.equal(stubOrg2.short_name)
    expect(res.json.args[0][0].cve_ids[0].requested_by.cna).to.equal(stubOrg.short_name)
    expect(res.json.args[0][0].cve_ids[0].requested_by.user).to.equal(stubUser.username)
  })
})


text:
const getConstants = require('../../../../src/constants').getConstants
const CONSTANTS = getConstants()
const year = '3000'

const secretariatHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'mitre',
  'CVE-API-USER': 'cpadro',
  'CVE-API-KEY': 'S96E4QT-SMT4YE3-KX03X6K-4615CED'
}

const userAHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'cisco',
  'CVE-API-USER': 'alopez',
  'CVE-API-KEY': 'SVXPHM9-1VXM0A8-QMG8WN0-29MASSE'
}

const userBHeader = {
  'content-type': 'application/json',
  'CVE-API-ORG': 'siemens',
  'CVE-API-USER': 'rgonz',
  'CVE-API-KEY': '006YPCK-14R46D6-KR24W1K-PJG5BVP'
}

const secretariatOrg = {
  UUID: '15fd129f-af00-4d8c-8f7b-e19b0587223f',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA, CONSTANTS.AUTH_ROLE_ENUM.SECRETARIAT]
  },
  name: 'The MITRE Corporation',
  policies: {
    id_quota: 1000
  },
  short_name: 'mitre',
  inUse: false
}

const secretariatUser = {
  UUID: 'e13186d5-ce3d-4fd9-aecd-8698c26897f2',
  org_UUID: secretariatOrg.UUID,
  name: {
    first: 'Cristina',
    last: 'Padro'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$+qGHEfH5h4/tk404iWBxFw$xV96/b4NvQVvlZIq57wTS8s7gfKzsfMXRiOyf3ffgcw',
  username: 'cpadro',
  active: true
}

const orgA = {
  UUID: '88c02595-c8f7-4864-a0e7-e09b3e1da691',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA]
  },
  name: 'Cisco',
  policies: {
    id_quota: 500
  },
  short_name: 'cisco',
  inUse: false
}

const userA = {
  UUID: '1fcbf829-81ae-4b53-a61d-9fa04711447f',
  org_UUID: orgA.UUID,
  name: {
    first: 'Armando',
    last: 'Lopez',
    middle: 'Jose'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$bHTrVB/WVMI+yscYe1Y1aQ$RdQkx9w9sME6z5W/2tyHu/6WcYGvi1JeY3KLbr+ioBg',
  username: 'alopez',
  active: true
}

const orgB = {
  UUID: 'c0a1d017-faa5-4608-92ff-5c938da17eff',
  authority: {
    active_roles: [CONSTANTS.AUTH_ROLE_ENUM.CNA]
  },
  name: 'Siemens',
  policies: {
    id_quota: 500
  },
  short_name: 'siemens',
  inUse: false
}

const userB = {
  UUID: '4121968f-cc2d-4680-b9b0-39e98a2182f6',
  org_UUID: orgB.UUID,
  name: {
    first: 'Rebecca',
    last: 'Gonzalez',
    middle: 'Andrea'
  },
  authority: {
    active_roles: []
  },
  secret: '$argon2i$v=19$m=4096,t=3,p=1$3q1N+kLqTivvqH1q+r1G5Q$7E+ZXrwagOmWaXFxnBbfaWwTyfpWBhsGMitaF82cx3Q',
  username: 'rgonz',
  active: true
}

const availableCveIds = [
  {
    cve_id: `CVE-${year}-20001`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-20002`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-20003`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-20004`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-20005`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  }
]

const availableCveIdsAB = []

const availableCveIdsA = [...availableCveIds]

const availableCveIdsB = [...availableCveIds]

const availableCveIdsC = [
  {
    cve_id: `CVE-${year}-0001`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  }
]

const cveIdsE = [
  {
    cve_id: `CVE-${year}-0001`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0002`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0003`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0004`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0005`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0006`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0007`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0008`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.RESERVED,
    owning_cna: secretariatOrg.UUID,
    reserved: Date.now(),
    requested_by: {
      cna: secretariatUser.org_UUID,
      user: secretariatUser.UUID
    }
  },
  {
    cve_id: `CVE-${year}-0009`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.RESERVED,
    owning_cna: secretariatOrg.UUID,
    reserved: Date.now(),
    requested_by: {
      cna: secretariatUser.org_UUID,
      user: secretariatUser.UUID
    }
  },
  {
    cve_id: `CVE-${year}-0010`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.RESERVED,
    owning_cna: secretariatOrg.UUID,
    reserved: Date.now(),
    requested_by: {
      cna: secretariatUser.org_UUID,
      user: secretariatUser.UUID
    }
  }
]

const availableCveIdsF = [
  {
    cve_id: `CVE-${year}-0001`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0002`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0003`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0004`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0005`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0006`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0007`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0008`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0009`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0010`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0011`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0012`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0013`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0014`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  },
  {
    cve_id: `CVE-${year}-0015`,
    cve_year: year,
    state: CONSTANTS.CVE_STATES.AVAILABLE,
    owning_cna: 'N/A',
    reserved: Date.now(),
    requested_by: {
      cna: 'N/A',
      user: 'N/A'
    }
  }
]

const availableCveIdsG = [...availableCveIdsF]

module.exports = {
  availableCveIds,
  availableCveIdsAB,
  availableCveIdsA,
  availableCveIdsB,
  availableCveIdsC,
  cveIdsE,
  availableCveIdsF,
  availableCveIdsG,
  secretariatHeader,
  userAHeader,
  userBHeader,
  secretariatOrg,
  secretariatUser,
  orgA,
  userA,
  orgB,
  userB,
  year
}


text:
const express = require('express')
const app = express()
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
const middleware = require('../../../../src/middleware/middleware')
app.use(middleware.createCtxAndReqUUID)

const idsA = []
const idsB = []
const getConstants = require('../../../../src/constants').getConstants
const errors = require('../../../../src/controller/cve-id.controller/error')
const error = new errors.CveIdControllerError()

const cveIdNonSeqFixtures = require('./mockObjects.non-sequential')
const cveIdController = require('../../../../src/controller/cve-id.controller/cve-id.controller')
const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware')

class CveIdReservePoolIncremented10IdsCaseAB1 {
  constructor () {
    this.docs = cveIdNonSeqFixtures.availableCveIdsAB
  }

  getCveIdDocuments () {
    return this.docs
  }

  async insertMany (documents) {
    documents.forEach(doc => {
      this.docs.push(doc)
    })
    return documents
  }

  async countDocuments () {
    return 0
  }

  async find (query, options) {
    const res = []
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) {
        if (res.length < options.limit) {
          res.push(this.docs[i])
        }
      }
    }

    if (res.length === 0) {
      return []
    }

    return res
  }

  async findOneAndUpdate (query, updatedCveId) {
    let index = -1
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) {
        index = i
        break
      }
    }

    if (index >= 0) {
      this.docs[index] = updatedCveId
      return this.docs[index]
    }

    return null
  }
}

class CveIdRangeReserveNonSequentialSuccessCaseAB1 {
  constructor () {
    const CONSTANTS = getConstants()

    this.year = '3000'
    this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
    this.cveIdRange.cve_year = this.year
    this.cveIdRange.ranges.general.top_id = 0
    this.cveIdRange.ranges.general.start = 0
    this.cveIdRange.ranges.general.end = 25
  }

  getCveIdRange () {
    return this.cveIdRange
  }

  async findOne () {
    return this.cveIdRange
  }

  async findOneAndUpdate (query, set) {
    if (query.$and !== undefined) {
      if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
      this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) {
        this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
        return this.cveIdRange
      } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) {
        this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
        return this.cveIdRange
      }
    } else if (query.cve_year === this.year) {
      this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
      return this.cveIdRange
    }

    return null
  }
}

class CveIdReservePoolIncremented10IdsCaseAB2 {
  constructor () {
    this.docs = cveIdNonSeqFixtures.availableCveIdsAB
  }

  getCveIdDocuments () {
    return this.docs
  }

  async insertMany (documents) {
    documents.forEach(doc => {
      this.docs.push(doc)
    })
    return documents
  }

  async countDocuments () {
    return 0
  }

  async find (query, options) {
    const res = []
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) {
        if (res.length < options.limit) {
          res.push(this.docs[i])
        }
      }
    }

    if (res.length === 0) {
      return []
    }

    return res
  }

  async findOneAndUpdate (query, updatedCveId) {
    let index = -1
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) {
        index = i
        break
      }
    }

    if (index >= 0) {
      this.docs[index] = updatedCveId
      return this.docs[index]
    }

    return null
  }
}

class CveIdRangeReserveNonSequentialSuccessCaseAB2 {
  constructor () {
    const CONSTANTS = getConstants()

    this.year = '3000'
    this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
    this.cveIdRange.cve_year = this.year
    this.cveIdRange.ranges.general.top_id = 25
    this.cveIdRange.ranges.general.start = 0
    this.cveIdRange.ranges.general.end = 25
  }

  getCveIdRange () {
    return this.cveIdRange
  }

  async findOne () {
    return this.cveIdRange
  }

  async findOneAndUpdate (query, set) {
    if (query.$and !== undefined) {
      if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
      this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) {
        this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
        return this.cveIdRange
      } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) {
        this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
        return this.cveIdRange
      }
    } else if (query.cve_year === this.year) {
      this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
      return this.cveIdRange
    }

    return null
  }
}

class UserReserveNonSequentialSuccessCaseAB {
  async findOneByUserNameAndOrgUUID (username) {
    if (username === cveIdNonSeqFixtures.userA.username) {
      return cveIdNonSeqFixtures.userA
    }

    return cveIdNonSeqFixtures.userB
  }
}

class OrgReserveNonSequentialSuccessCaseAB {
  async isSecretariat () {
    return false
  }

  async findOneAndUpdate (query) {
    if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === false) {
      cveIdNonSeqFixtures.orgA.inUse = true
      return cveIdNonSeqFixtures.orgA
    } else if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === true) {
      cveIdNonSeqFixtures.orgA.inUse = false
      return null
    } else if (query.short_name === cveIdNonSeqFixtures.orgB.short_name && cveIdNonSeqFixtures.orgB.inUse === false) {
      cveIdNonSeqFixtures.orgB.inUse = true
      return cveIdNonSeqFixtures.orgB
    } else if (query.short_name === cveIdNonSeqFixtures.orgB.short_name && cveIdNonSeqFixtures.orgB.inUse === true) {
      cveIdNonSeqFixtures.orgB.inUse = false
      return null
    }
  }

  async findOneByShortName (shortname) {
    if (shortname === cveIdNonSeqFixtures.orgA.short_name) {
      return cveIdNonSeqFixtures.orgA
    }

    return cveIdNonSeqFixtures.orgB
  }

  async getOrgUUID (shortname) {
    if (shortname === cveIdNonSeqFixtures.orgA.short_name) {
      return cveIdNonSeqFixtures.orgA.UUID
    }

    return cveIdNonSeqFixtures.orgB.UUID
  }
}

const cveIdTestRepoAB1 = new CveIdReservePoolIncremented10IdsCaseAB1()
const cveIdTestRepoAB2 = new CveIdReservePoolIncremented10IdsCaseAB2()
const cveIdRangeTestRepoAB2 = new CveIdRangeReserveNonSequentialSuccessCaseAB2()

describe('Testing the non sequential reservation (Case AB) of POST /cve-id endpoint in CveId Controller', () => {
  context('Positive Tests', () => {
    it('User A reserves 10 ids', (done) => {
      const cveIdRepo = new CveIdReservePoolIncremented10IdsCaseAB1()
      const cveIdRangeRepo = new CveIdRangeReserveNonSequentialSuccessCaseAB1()
      const userRepo = new UserReserveNonSequentialSuccessCaseAB()
      const orgRepo = new OrgReserveNonSequentialSuccessCaseAB()

      app.route('/cve-id-reserve-user-a-10-ids')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return cveIdRepo },
            getCveIdRangeRepository: () => { return cveIdRangeRepo },
            getUserRepository: () => { return userRepo },
            getOrgRepository: () => { return orgRepo }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-user-a-10-ids?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) // 5
        .set(cveIdNonSeqFixtures.userAHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10)

          // check that the reserved cve ids were reserved by userA
          res.body.cve_ids.forEach(obj => {
            idsA.push(obj.cve_id)
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.greaterThan(0).and.lessThan(26) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20025
            expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED
            expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name)
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name)
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username)
          })

          // check that no duplicate cve ids were reserved
          res.body.cve_ids.forEach(id1 => {
            let counter = 0
            res.body.cve_ids.forEach(id2 => {
              if (id1 === id2) {
                counter++
              }
            })
            expect(counter).to.equal(1)
          })

          // check total count of reserved ids by userA
          const docs = cveIdTestRepoAB1.getCveIdDocuments()
          let reservedCounter = 0
          docs.forEach(doc => {
            if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') {
              reservedCounter++
            }
          })
          expect(reservedCounter).to.equal(10)

          // check count of available ids
          let availableCounter = 0
          docs.forEach(doc => {
            if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') {
              availableCounter++
            }
          })
          expect(availableCounter).to.equal(15)

          // check that unreserved ids by userA are available
          const rangeDoc = cveIdRangeRepo.getCveIdRange()
          const topId = rangeDoc.ranges.general.top_id
          const availableDocs = []
          for (let i = 0; i < docs.length; i++) {
            let contains = false
            for (let j = 0; j < idsA.length; j++) {
              if (docs[i].cve_id === idsA[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) {
                contains = true
                break
              }
            }
            if (!contains) {
              availableDocs.push(docs[i])
            }
          }
          expect(availableDocs).to.have.lengthOf(15)
          availableDocs.forEach(obj => {
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id
            expect(obj).to.have.property('state').and.to.equal('AVAILABLE')
            expect(obj).to.have.property('owning_cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal('N/A')
          })

          done()
        })
    })

    it('User B reserves 10 ids', (done) => {
      app.route('/cve-id-reserve-user-b-10-ids')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseAB2() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseAB2() },
            getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseAB() },
            getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseAB() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-user-b-10-ids?short_name=${cveIdNonSeqFixtures.orgB.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`) // 20
        .set(cveIdNonSeqFixtures.userBHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdNonSeqFixtures.orgB.policies.id_quota - 10).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10)

          // check that the reserved cve ids were reserved by userB
          res.body.cve_ids.forEach(obj => {
            idsB.push(obj.cve_id)
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.greaterThan(0).and.lessThan(26) // Available id range: CVE-YYYY-0001 to CVE-YYYY-0025
            expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED
            expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgB.short_name)
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgB.short_name)
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userB.username)
          })

          // check that no duplicate cve ids were reserved
          res.body.cve_ids.forEach(id1 => {
            let counter = 0
            res.body.cve_ids.forEach(id2 => {
              if (id1 === id2) {
                counter++
              }
            })
            expect(counter).to.equal(1)
          })

          // check total count of reserved ids by userB
          const docs = cveIdTestRepoAB2.getCveIdDocuments()
          let reservedCounter = 0
          docs.forEach(doc => {
            if (doc.owning_cna === cveIdNonSeqFixtures.orgB.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') {
              reservedCounter++
            }
          })
          expect(reservedCounter).to.equal(10)

          // check count of available ids
          let availableCounter = 0
          docs.forEach(doc => {
            if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') {
              availableCounter++
            }
          })
          expect(availableCounter).to.equal(5)

          // check that unreserved ids by userA or userB are available
          const rangeDoc = cveIdRangeTestRepoAB2.getCveIdRange()
          const topId = rangeDoc.ranges.general.top_id
          const availableDocs = []
          for (let i = 0; i < docs.length; i++) {
            let contains = false
            for (let j = 0; j < idsA.length; j++) {
              if (docs[i].cve_id === idsA[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) {
                contains = true
                break
              }
            }

            if (!contains) {
              for (let j = 0; j < idsB.length; j++) {
                if (docs[i].cve_id === idsB[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) {
                  contains = true
                  break
                }
              }
            }

            if (!contains) {
              availableDocs.push(docs[i])
            }
          }
          expect(availableDocs).to.have.lengthOf(5)
          availableDocs.forEach(obj => {
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id
            expect(obj).to.have.property('state').and.to.equal('AVAILABLE')
            expect(obj).to.have.property('owning_cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal('N/A')
          })

          done()
        })
    })
  })

  context('Negative Tests', () => {
    it(`User A tries to reserve 10 more ids but the CveId Range document for year ${cveIdNonSeqFixtures.year} is full`, (done) => {
      class CveIdReservePoolIncremented10IdsCaseAB3 {
        constructor () {
          this.docs = cveIdNonSeqFixtures.availableCveIdsAB
        }

        getCveIdDocuments () {
          return this.docs
        }

        async insertMany (documents) {
          documents.forEach(doc => {
            this.docs.push(doc)
          })
          return documents
        }

        async countDocuments () {
          return 10
        }

        async find (query, options) {
          const res = []
          for (let i = 0; i < this.docs.length; i++) {
            if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) {
              if (res.length < options.limit) {
                res.push(this.docs[i])
              }
            }
          }

          if (res.length === 0) {
            return []
          }

          return res
        }

        async findOneAndUpdate (query, updatedCveId) {
          let index = -1
          for (let i = 0; i < this.docs.length; i++) {
            if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) {
              index = i
              break
            }
          }

          if (index >= 0) {
            this.docs[index] = updatedCveId
            return this.docs[index]
          }

          return null
        }
      }

      class CveIdRangeReserveNonSequentialSuccessCaseAB3 {
        constructor () {
          const CONSTANTS = getConstants()

          this.year = '3000'
          this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
          this.cveIdRange.cve_year = this.year
          this.cveIdRange.ranges.general.top_id = 25
          this.cveIdRange.ranges.general.start = 0
          this.cveIdRange.ranges.general.end = 25
        }

        getCveIdRange () {
          return this.cveIdRange
        }

        async findOne () {
          return this.cveIdRange
        }

        async findOneAndUpdate (query, set) {
          if (query.$and !== undefined) {
            if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
            this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) {
              this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
              return this.cveIdRange
            } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) {
              this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
              return this.cveIdRange
            }
          } else if (query.cve_year === this.year) {
            this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
            return this.cveIdRange
          }

          return null
        }
      }

      app.route('/cve-id-reserve-user-a-10-ids-year-full')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReservePoolIncremented10IdsCaseAB3() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveNonSequentialSuccessCaseAB3() },
            getUserRepository: () => { return new UserReserveNonSequentialSuccessCaseAB() },
            getOrgRepository: () => { return new OrgReserveNonSequentialSuccessCaseAB() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-user-a-10-ids-year-full?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`)
        .set(cveIdNonSeqFixtures.userAHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.yearRangeFull(cveIdNonSeqFixtures.year)
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)

          // check that no duplicate cve ids were reserved by userA and userB
          idsA.forEach(id1 => {
            let isDisjoint = true
            idsB.forEach(id2 => {
              if (id1 === id2) {
                isDisjoint = false
              }
            })
            expect(isDisjoint).to.equal(true) // pass: The intersection set between idsA and idsB is null
          })

          done()
        })
    })
  })
})


text:
const express = require('express')
const app = express()
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
const middleware = require('../../../../src/middleware/middleware')
app.use(middleware.createCtxAndReqUUID)

const ids = []
const getConstants = require('../../../../src/constants').getConstants
const errors = require('../../../../src/controller/cve-id.controller/error')
const error = new errors.CveIdControllerError()

const cveIdNonSeqFixtures = require('./mockObjects.non-sequential')
const cveIdController = require('../../../../src/controller/cve-id.controller/cve-id.controller')
const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware')

class CveIdReservePoolIncremented10Ids {
  constructor () {
    this.docs = cveIdNonSeqFixtures.availableCveIds
  }

  getCveIdDocuments () {
    return this.docs
  }

  async insertMany (documents) {
    documents.forEach(doc => {
      this.docs.push(doc)
    })
    return documents
  }

  async countDocuments () {
    return 0
  }

  async find (query, options) {
    const res = []
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_year.toString() === query.cve_year && this.docs[i].state === query.state) {
        if (res.length < options.limit) {
          res.push(this.docs[i])
        }
      }
    }

    if (res.length === 0) {
      return []
    }

    return res
  }

  async findOneAndUpdate (query, updatedCveId) {
    let index = -1
    for (let i = 0; i < this.docs.length; i++) {
      if (this.docs[i].cve_id === query.cve_id && this.docs[i].state === query.state) {
        index = i
        break
      }
    }

    if (index >= 0) {
      this.docs[index] = updatedCveId
      return this.docs[index]
    }

    return null
  }
}

class CveIdRangeReserveNonSequentialSuccess {
  constructor () {
    const CONSTANTS = getConstants()

    this.year = '3000'
    this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
    this.cveIdRange.cve_year = this.year
    this.cveIdRange.ranges.general.top_id = 20005
    this.cveIdRange.ranges.general.end = 30000
  }

  getCveIdRange () {
    return this.cveIdRange
  }

  async findOne () {
    return this.cveIdRange
  }

  async findOneAndUpdate (query, set) {
    if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
    this.cveIdRange.ranges.general.end >= query.$and[1]['ranges.general.end'].$gte) {
      this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
      return this.cveIdRange
    } else if (query.$and[0].cve_year === this.year && set.$inc['ranges.general.top_id'] !== undefined) {
      this.cveIdRange.ranges.general.top_id = set.$set['ranges.general.top_id']
      return this.cveIdRange
    }

    return null
  }
}

const cveIdTestRepo = new CveIdReservePoolIncremented10Ids()

describe('Testing the non sequential reservation (Base Case) of POST /cve-id endpoint in CveId Controller', () => {
  context('Negative Tests', () => {
    it('CveId Range document for year 2025 does not exist', (done) => {
      class CveIdReserveNonSequentialIsFull {
        async countDocuments () {
          return 0
        }
      }

      class CveIdRangeReserveYearDoesntExist {
        async findOne () {
          return null
        }
      }

      class NullUserRepo {
        async getUserUUID () {
          return null
        }

        async findOneByUserNameAndOrgUUID () {
          return null
        }

        async isAdmin () {
          return null
        }
      }

      class OrgReserveNonSequentialYearDoesntExist {
        async isSecretariat () {
          return false
        }

        async findOneByShortName () {
          return cveIdNonSeqFixtures.orgA
        }

        async findOneAndUpdate (query) {
          if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === false) {
            cveIdNonSeqFixtures.orgA.inUse = true
            return cveIdNonSeqFixtures.orgA
          } else if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === true) {
            cveIdNonSeqFixtures.orgA.inUse = false
            return null
          }
        }
      }

      app.route('/cve-id-reserve-nonsequential-2025-doesnt-exist')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReserveNonSequentialIsFull() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveYearDoesntExist() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveNonSequentialYearDoesntExist() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-nonsequential-2025-doesnt-exist?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=2025&amount=10&batch_type=non-sequential`)
        .set(cveIdNonSeqFixtures.userAHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = cveIdNonSeqFixtures.orgA.policies.id_quota.toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.cannotReserveForYear('2025')
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })
  })

  context('Positive Tests', () => {
    it('Pool is incremented and 10 ids are reserved', (done) => {
      class UserReserveNonSequentialSuccess {
        async findOneByUserNameAndOrgUUID () {
          return cveIdNonSeqFixtures.userA
        }
      }

      class OrgReserveNonSequentialSuccess {
        async isSecretariat () {
          return false
        }

        async findOneByShortName () {
          return cveIdNonSeqFixtures.orgA
        }

        async findOneAndUpdate (query) {
          if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === false) {
            cveIdNonSeqFixtures.orgA.inUse = true
            return cveIdNonSeqFixtures.orgA
          } else if (query.short_name === cveIdNonSeqFixtures.orgA.short_name && cveIdNonSeqFixtures.orgA.inUse === true) {
            cveIdNonSeqFixtures.orgA.inUse = false
            return null
          }
        }

        async getOrgUUID () {
          return cveIdNonSeqFixtures.orgA.UUID
        }
      }

      const cveIdRepo = new CveIdReservePoolIncremented10Ids()
      const cveIdRangeRepo = new CveIdRangeReserveNonSequentialSuccess()
      const userRepo = new UserReserveNonSequentialSuccess()
      const orgRepo = new OrgReserveNonSequentialSuccess()

      app.route('/cve-id-reserve-nonsequential-3000-10-ids')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return cveIdRepo },
            getCveIdRangeRepository: () => { return cveIdRangeRepo },
            getUserRepository: () => { return userRepo },
            getOrgRepository: () => { return orgRepo }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-nonsequential-3000-10-ids?short_name=${cveIdNonSeqFixtures.orgA.short_name}&cve_year=${cveIdNonSeqFixtures.year}&amount=10&batch_type=non-sequential`)
        .set(cveIdNonSeqFixtures.userAHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdNonSeqFixtures.orgA.policies.id_quota - 10).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('cve_ids').and.to.be.a('array').and.to.have.lengthOf(10)

          // check that the reserved cve ids were reserved by userA
          res.body.cve_ids.forEach(obj => {
            ids.push(obj.cve_id)
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.greaterThan(20000).and.lessThan(20111) // Available id range: CVE-YYYY-20001 to CVE-YYYY-20110
            expect(obj).to.have.property('state').and.to.equal('RESERVED') // checking that all CVE IDs returned are RESERVED
            expect(obj).to.have.property('owning_cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name)
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdNonSeqFixtures.orgA.short_name)
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdNonSeqFixtures.userA.username)
          })

          // check that no duplicate cve ids were reserved
          res.body.cve_ids.forEach(id1 => {
            let counter = 0
            res.body.cve_ids.forEach(id2 => {
              if (id1 === id2) {
                counter++
              }
            })
            expect(counter).to.equal(1)
          })

          // check total count of reserved ids by userA
          const docs = cveIdTestRepo.getCveIdDocuments()
          let reservedCounter = 0
          docs.forEach(doc => {
            if (doc.owning_cna === cveIdNonSeqFixtures.orgA.UUID && doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'RESERVED') {
              reservedCounter++
            }
          })
          expect(reservedCounter).to.equal(10)

          // check count of available ids
          let availableCounter = 0
          docs.forEach(doc => {
            if (doc.cve_year === cveIdNonSeqFixtures.year && doc.state === 'AVAILABLE') {
              availableCounter++
            }
          })
          expect(availableCounter).to.equal(100)

          // check that unreserved ids by userA are available
          const rangeDoc = cveIdRangeRepo.getCveIdRange()
          const topId = rangeDoc.ranges.general.top_id
          const availableDocs = []
          for (let i = 0; i < docs.length; i++) {
            let contains = false
            for (let j = 0; j < ids.length; j++) {
              if (docs[i].cve_id === ids[j] && docs[i].cve_year === cveIdNonSeqFixtures.year) {
                contains = true
                break
              }
            }
            if (!contains) {
              availableDocs.push(docs[i])
            }
          }
          expect(availableDocs).to.have.lengthOf(100)
          availableDocs.forEach(obj => {
            const index = parseInt(obj.cve_id.match(/\d+$/g))
            expect(index).to.be.lessThan(topId + 1) // check that the id is less than the current top id
            expect(obj).to.have.property('state').and.to.equal('AVAILABLE')
            expect(obj).to.have.property('owning_cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal('N/A')
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal('N/A')
          })

          done()
        })
    })
  })
})


text:
const express = require('express')
const app = express()
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
const middleware = require('../../../../src/middleware/middleware')
app.use(middleware.createCtxAndReqUUID)

const year20 = 2020
const getConstants = require('../../../../src/constants').getConstants
const errors = require('../../../../src/controller/cve-id.controller/error')
const error = new errors.CveIdControllerError()

const cveIdFixtures = require('../mockObjects.cve-id')
const cveIdController = require('../../../../src/controller/cve-id.controller/cve-id.controller')
const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware')

class NullCveIdRepo {
  async countDocuments () {
    return null
  }
}

class NullUserRepo {
  async getUserUUID () {
    return null
  }

  async findOneByUserNameAndOrgUUID () {
    return null
  }

  async isAdmin () {
    return null
  }
}

class OrgReserveShortNameUndefined {
  async isSecretariat () {
    return true
  }
}

class OrgReserveAmountLargerThanNonSequential {
  async isSecretariat () {
    return true
  }

  async findOneByShortName () {
    return cveIdFixtures.org
  }

  async findOneAndUpdate (query) {
    if (query.short_name === cveIdFixtures.org.short_name && cveIdFixtures.org.inUse === false) {
      cveIdFixtures.org.inUse = true
      return cveIdFixtures.org
    } else if (query.short_name === cveIdFixtures.org.short_name && cveIdFixtures.org.inUse === true) {
      cveIdFixtures.org.inUse = false
      return null
    }
  }
}

describe('Testing the general logic of POST /cve-id endpoint in CveId Controller', () => {
  context('Negative Tests', () => {
    it('Requester is not a user of the same org or the secretariat', (done) => {
      class OrgReserveNotOwningOrg {
        async isSecretariat () {
          return false
        }
      }

      app.route('/cve-id-reserve-not-owning-org')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveNotOwningOrg() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-not-owning-org?cve_year=${year20}&amount=1`)
        .set(cveIdFixtures.orgHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.orgCannotReserveForOther()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Shortname query parameter is undefined', (done) => {
      app.route('/cve-id-reserve-shortname-undefined')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveShortNameUndefined() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-shortname-undefined?cve_year=${year20}&amount=1`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.noOrgShortName()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Year query parameter is undefined', (done) => {
      app.route('/cve-id-reserve-year-undefined')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveShortNameUndefined() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-year-undefined?short_name=${cveIdFixtures.owningOrg.short_name}&amount=1`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.noYear()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Amount query parameter is undefined', (done) => {
      app.route('/cve-id-reserve-amount-undefined')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveShortNameUndefined() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-amount-undefined?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year20}`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.noAmount()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Amount query parameter is <= 0', (done) => {
      app.route('/cve-id-reserve-amount-0')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveShortNameUndefined() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-amount-0?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year20}&amount=0`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.invalidAmount()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Amount query parameter is > 1 and batchType is undefined', (done) => {
      app.route('/cve-id-reserve-batchtype-undefined')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveShortNameUndefined() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-batchtype-undefined?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year20}&amount=5`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.noBatchType()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Org does not exist', (done) => {
      class OrgReserveOrgDoesntExist {
        async isSecretariat () {
          return true
        }

        async findOneByShortName () {
          return null
        }
      }

      app.route('/cve-id-reserve-org-doesnt-exist')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveOrgDoesntExist() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-org-doesnt-exist?short_name=${cveIdFixtures.nonExistentOrg.short_name}&cve_year=${year20}&amount=1`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.orgDne(cveIdFixtures.nonExistentOrg.short_name, 'short_name', 'query')
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Amount query parameter is greater than max nonsequential amount allowed', (done) => {
      const CONSTANTS = getConstants()

      app.route('/cve-id-reserve-amount-greater-nonsequential')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveAmountLargerThanNonSequential() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-amount-greater-nonsequential?short_name=${cveIdFixtures.org.short_name}&cve_year=${year20}&amount=${(CONSTANTS.NONSEQUENTIAL_MAX_AMOUNT + 1)}&batch_type=nonsequential`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.overNonSequentialMaxAmount()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('Amount query parameter is > than id_quota', (done) => {
      class OrgReserveAmountGreaterIdQuota {
        async isSecretariat () {
          return true
        }

        async findOneByShortName () {
          return cveIdFixtures.org
        }
      }

      app.route('/cve-id-reserve-amount-greater-id-quota')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveAmountGreaterIdQuota() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-amount-greater-id-quota?short_name=${cveIdFixtures.org.short_name}&cve_year=${year20}&amount=700&batch_type=sequential`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.overIdQuota(res.body.details)
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          expect(res.body.details).to.equal(errObj.details)
          done()
        })
    })

    it('Invalid batchType', (done) => {
      app.route('/cve-id-reserve-invalid-batchtype')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveAmountLargerThanNonSequential() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-invalid-batchtype?short_name=${cveIdFixtures.org.short_name}&cve_year=${year20}&amount=1&batch_type=pair`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          expect(res).to.have.status(400)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.invalidBatchType()
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })
  })
})


text:
const express = require('express')
const app = express()
const chai = require('chai')
const expect = chai.expect
chai.use(require('chai-http'))

// Body Parser Middleware
app.use(express.json()) // Allows us to handle raw JSON data
app.use(express.urlencoded({ extended: false })) // Allows us to handle url encoded data
const middleware = require('../../../../src/middleware/middleware')
app.use(middleware.createCtxAndReqUUID)

const year20 = 2020
const year21 = 2021
const getConstants = require('../../../../src/constants').getConstants
const errors = require('../../../../src/controller/cve-id.controller/error')
const error = new errors.CveIdControllerError()

const cveIdFixtures = require('../mockObjects.cve-id')
const cveIdController = require('../../../../src/controller/cve-id.controller/cve-id.controller')
const cveIdParams = require('../../../../src/controller/cve-id.controller/cve-id.middleware')

class NullUserRepo {
  async getUserUUID () {
    return null
  }

  async findOneByUserNameAndOrgUUID () {
    return null
  }

  async isAdmin () {
    return null
  }
}

class CveIdReserveSequentialPriorityIsFull {
  async insertMany () {
    return null
  }

  async countDocuments () {
    return 0
  }
}

class UserReserveSequentialPriorityIsFull {
  async findOneByUserNameAndOrgUUID () {
    return cveIdFixtures.owningOrgUser
  }
}

class OrgReserveSequentialPriorityIsFull {
  async isSecretariat () {
    return false
  }

  async findOneByShortName () {
    return cveIdFixtures.owningOrg
  }

  async findOneAndUpdate (query) {
    if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === false) {
      cveIdFixtures.owningOrg.inUse = true
      return cveIdFixtures.owningOrg
    } else if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === true) {
      cveIdFixtures.owningOrg.inUse = false
      return null
    }
  }

  async getOrgUUID () {
    return cveIdFixtures.owningOrg.UUID
  }
}

describe('Testing the priority reservation of POST /cve-id endpoint in CveId Controller', () => {
  context('Negative Tests', () => {
    it('CveId Range document for year 2025 does not exist', (done) => {
      class NullCveIdRepo {
        async countDocuments () {
          return null
        }
      }

      class CveIdRangeReserveYearDoesntExist {
        async findOne () {
          return null
        }
      }

      class OrgReserveYear2025RangeDoesntExist {
        async isSecretariat () {
          return true
        }

        async findOneByShortName () {
          return cveIdFixtures.owningOrg
        }

        async findOneAndUpdate (query) {
          if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === false) {
            cveIdFixtures.owningOrg.inUse = true
            return cveIdFixtures.owningOrg
          } else if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === true) {
            cveIdFixtures.owningOrg.inUse = false
            return null
          }
        }
      }

      app.route('/cve-id-reserve-year-2025-doesnt-exist')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new NullCveIdRepo() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveYearDoesntExist() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveYear2025RangeDoesntExist() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-year-2025-doesnt-exist?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=2025&amount=1`)
        .set(cveIdFixtures.secretariatHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = cveIdFixtures.owningOrg.policies.id_quota.toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.cannotReserveForYear('2025')
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })

    it('CveId Range document for year 2021 is full', (done) => {
      const CONSTANTS = getConstants()

      class CveIdRangeReserveSequentialIsFull {
        constructor () {
          this.year = '2021'
          this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
          this.cveIdRange.cve_year = this.year
          this.cveIdRange.ranges.priority.top_id = this.cveIdRange.ranges.priority.end
          this.cveIdRange.ranges.general.top_id = this.cveIdRange.ranges.general.end
        }

        async findOne () {
          return this.cveIdRange
        }

        async findOneAndUpdate () {
          return null
        }
      }

      class OrgReserveSequentialIsFull {
        async isSecretariat () {
          return false
        }

        async findOneByShortName () {
          return cveIdFixtures.owningOrg
        }

        async findOneAndUpdate (query) {
          if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === false) {
            cveIdFixtures.owningOrg.inUse = true
            return cveIdFixtures.owningOrg
          } else if (query.short_name === cveIdFixtures.owningOrg.short_name && cveIdFixtures.owningOrg.inUse === true) {
            cveIdFixtures.owningOrg.inUse = false
            return null
          }
        }
      }

      app.route('/cve-id-reserve-range-2021-full')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReserveSequentialPriorityIsFull() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveSequentialIsFull() },
            getUserRepository: () => { return new NullUserRepo() },
            getOrgRepository: () => { return new OrgReserveSequentialIsFull() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      chai.request(app)
        .post(`/cve-id-reserve-range-2021-full?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year21}&amount=1`)
        .set(cveIdFixtures.owningOrgHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdFixtures.owningOrg.policies.id_quota).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(403)
          expect(res).to.have.property('body').and.to.be.a('object')
          const errObj = error.yearRangeFull(year21)
          expect(res.body.error).to.equal(errObj.error)
          expect(res.body.message).to.equal(errObj.message)
          done()
        })
    })
  })

  context('Positive Tests', () => {
    it('Cve ID is reserved in the sequential block because the priority block for year 2021 is full', (done) => {
      const CONSTANTS = getConstants()

      class CveIdRangeReserveSequentialPriorityIsFull {
        constructor () {
          this.year = '2021'
          this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
          this.cveIdRange.cve_year = this.year
          this.cveIdRange.ranges.priority.top_id = this.cveIdRange.ranges.priority.end
          this.cveIdRange.ranges.general.top_id = this.cveIdRange.ranges.general.end - 1
        }

        async findOne () {
          return this.cveIdRange
        }

        async findOneAndUpdate (query, set) {
          if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.priority.top_id'] !== undefined &&
          this.cveIdRange.ranges.priority.top_id < this.cveIdRange.ranges.priority.end) {
            this.cveIdRange.ranges.priority.top_id += set.$inc['ranges.priority.top_id']
            return this.cveIdRange
          } else if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
          this.cveIdRange.ranges.general.end > this.cveIdRange.ranges.general.top_id) {
            this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
            return this.cveIdRange
          }

          return null
        }
      }

      app.route('/cve-id-reserve-sequential-block-priority-full')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReserveSequentialPriorityIsFull() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveSequentialPriorityIsFull() },
            getUserRepository: () => { return new UserReserveSequentialPriorityIsFull() },
            getOrgRepository: () => { return new OrgReserveSequentialPriorityIsFull() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      const top = CONSTANTS.DEFAULT_CVE_ID_RANGE.ranges.general.end - 1
      const count = String(top + 1).padStart(4, '0')

      chai.request(app)
        .post(`/cve-id-reserve-sequential-block-priority-full?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year21}&amount=1`)
        .set(cveIdFixtures.owningOrgHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdFixtures.owningOrg.policies.id_quota - 1).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('cve_ids').and.to.be.a('array')
          res.body.cve_ids.forEach(obj => {
            expect(obj).to.have.property('cve_id').and.to.equal(`CVE-${year21}-${count}`)
            expect(obj).to.have.property('state').and.to.equal('RESERVED')
            expect(obj).to.have.property('owning_cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdFixtures.owningOrgUser.username)
          })
          done()
        })
    })

    it('Cve ID is reserved in the priority block', (done) => {
      const CONSTANTS = getConstants()

      class CveIdRangeReserveSequentialPriority {
        constructor () {
          this.year = '2020'
          this.cveIdRange = Object.assign({}, CONSTANTS.DEFAULT_CVE_ID_RANGE)
          this.cveIdRange.cve_year = this.year
          this.cveIdRange.ranges.priority.top_id = 0
          this.cveIdRange.ranges.general.top_id = this.cveIdRange.ranges.priority.end
        }

        async findOne () {
          return this.cveIdRange
        }

        async findOneAndUpdate (query, set) {
          if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.priority.top_id'] !== undefined &&
          this.cveIdRange.ranges.priority.top_id < this.cveIdRange.ranges.priority.end) {
            this.cveIdRange.ranges.priority.top_id += set.$inc['ranges.priority.top_id']
            return this.cveIdRange
          } else if (query.$and[0].cve_year === this.year && query.$and[1]['ranges.general.end'] !== undefined &&
          this.cveIdRange.ranges.general.end > this.cveIdRange.ranges.general.top_id) {
            this.cveIdRange.ranges.general.top_id += set.$inc['ranges.general.top_id']
            return this.cveIdRange
          }

          return null
        }
      }

      app.route('/cve-id-reserve-complete')
        .post((req, res, next) => {
          const factory = {
            getCveIdRepository: () => { return new CveIdReserveSequentialPriorityIsFull() },
            getCveIdRangeRepository: () => { return new CveIdRangeReserveSequentialPriority() },
            getUserRepository: () => { return new UserReserveSequentialPriorityIsFull() },
            getOrgRepository: () => { return new OrgReserveSequentialPriorityIsFull() }
          }
          req.ctx.repositories = factory
          next()
        }, cveIdParams.parsePostParams, cveIdController.CVEID_RESERVE)

      const top = 0
      const count = String(top + 1).padStart(4, '0')

      chai.request(app)
        .post(`/cve-id-reserve-complete?short_name=${cveIdFixtures.owningOrg.short_name}&cve_year=${year20}&amount=1`)
        .set(cveIdFixtures.owningOrgHeader)
        .end((err, res) => {
          if (err) {
            done(err)
          }

          const quotaHeader = (cveIdFixtures.owningOrg.policies.id_quota - 1).toString()
          expect(res.header).to.have.property('cve-api-remaining-quota').and.to.equal(quotaHeader)

          expect(res).to.have.status(200)
          expect(res).to.have.property('body').and.to.be.a('object')
          expect(res.body).to.have.property('cve_ids').and.to.be.a('array')
          res.body.cve_ids.forEach(obj => {
            expect(obj).to.have.property('cve_id').and.to.equal(`CVE-${year20}-${count}`)
            expect(obj).to.have.property('state').and.to.equal('RESERVED')
            expect(obj).to.have.property('owning_cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
            expect(obj).to.have.nested.property('requested_by.cna').and.to.equal(cveIdFixtures.owningOrg.short_name)
            expect(obj).to.have.nested.property('requested_by.user').and.to.equal(cveIdFixtures.owningOrgUser.username)
          })
          done()
        })
    })
  })
})