1
0
Fork 0
mirror of https://github.com/overleaf/overleaf.git synced 2025-04-22 14:38:08 +00:00

Merge pull request from overleaf/jpa-spd-mocks-core

[tests] rebased refactoring of acceptance test mocks

GitOrigin-RevId: dd8b7d69c507aa1270b6fb165b1339bc8a7d6415
This commit is contained in:
Jakob Ackermann 2021-02-25 12:22:24 +00:00 committed by Copybot
parent bc4f5a687a
commit 4a6af88760
42 changed files with 1016 additions and 858 deletions

View file

@ -4,10 +4,6 @@ const User = require('./helpers/User')
const request = require('./helpers/request')
const settings = require('settings-sharelatex')
require('./helpers/MockChatApi')
require('./helpers/MockDocstoreApi')
require('./helpers/MockDocUpdaterApi')
const expectErrorResponse = require('./helpers/expectErrorResponse')
function tryReadAccess(user, projectId, test, callback) {

View file

@ -6,10 +6,15 @@ const settings = require('settings-sharelatex')
const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
const { Subscription } = require('../../../app/src/models/Subscription')
const SubscriptionViewModelBuilder = require('../../../app/src/Features/Subscription/SubscriptionViewModelBuilder')
const MockDocstoreApi = require('./helpers/MockDocstoreApi')
const MockFileStoreApi = require('./helpers/MockFileStoreApi')
require('./helpers/MockV1Api')
require('./helpers/MockProjectHistoryApi')
const MockDocstoreApiClass = require('./mocks/MockDocstoreApi')
const MockFilestoreApiClass = require('./mocks/MockFilestoreApi')
let MockDocstoreApi, MockFilestoreApi
before(function() {
MockDocstoreApi = MockDocstoreApiClass.instance()
MockFilestoreApi = MockFilestoreApiClass.instance()
})
describe('Deleting a user', function() {
beforeEach(function(done) {
@ -252,7 +257,7 @@ describe('Deleting a project', function() {
done()
}
)
MockFileStoreApi.files[this.projectId.toString()] = {
MockFilestoreApi.files[this.projectId.toString()] = {
dummyFile: 'wombat'
}
})
@ -293,7 +298,7 @@ describe('Deleting a project', function() {
})
it('Should destroy the files', function(done) {
expect(MockFileStoreApi.files[this.projectId.toString()]).to.exist
expect(MockFilestoreApi.files[this.projectId.toString()]).to.exist
request.post(
`/internal/project/${this.projectId}/expire-deleted-project`,
@ -308,7 +313,7 @@ describe('Deleting a project', function() {
expect(error).not.to.exist
expect(res.statusCode).to.equal(200)
expect(MockFileStoreApi.files[this.projectId.toString()]).not.to
expect(MockFilestoreApi.files[this.projectId.toString()]).not.to
.exist
done()
}

View file

@ -3,9 +3,6 @@ const request = require('./helpers/request')
const { expect } = require('chai')
const settings = require('settings-sharelatex')
const { ObjectId } = require('mongodb')
require('./helpers/MockDocstoreApi')
require('./helpers/MockV1Api')
require('./helpers/MockProjectHistoryApi')
describe('DocUpdate', function() {
beforeEach(function(done) {

View file

@ -1,8 +1,5 @@
const User = require('./helpers/User')
const { expect } = require('chai')
require('./helpers/MockDocstoreApi')
require('./helpers/MockV1Api')
require('./helpers/MockProjectHistoryApi')
describe('EditorHttpController', function() {
beforeEach('login', function(done) {

View file

@ -19,8 +19,15 @@ const User = require('./helpers/User')
const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
const ExportsHandler = require('../../../app/src/Features/Exports/ExportsHandler.js')
const MockProjectHistoryApi = require('./helpers/MockProjectHistoryApi')
const MockV1Api = require('./helpers/MockV1Api')
const MockProjectHistoryApiClass = require('./mocks/MockProjectHistoryApi')
const MockV1ApiClass = require('./mocks/MockV1Api')
let MockProjectHistoryApi, MockV1Api
before(function() {
MockV1Api = MockV1ApiClass.instance()
MockProjectHistoryApi = MockProjectHistoryApiClass.instance()
})
describe('Exports', function() {
beforeEach(function(done) {
@ -50,7 +57,6 @@ describe('Exports', function() {
MockProjectHistoryApi.setProjectVersion(this.project_id, this.version)
this.export_id = Math.floor(Math.random() * 10000)
MockV1Api.setExportId(this.export_id)
MockV1Api.clearExportParams()
return this.owner.request(
{
method: 'POST',

View file

@ -22,10 +22,16 @@ const { Subscription } = require('../../../app/src/models/Subscription')
const { User } = require('../../../app/src/models/User')
const FeaturesUpdater = require('../../../app/src/Features/Subscription/FeaturesUpdater')
const MockV1Api = require('./helpers/MockV1Api')
const MockV1ApiClass = require('./mocks/MockV1Api')
const logger = require('logger-sharelatex')
logger.logger.level('error')
let MockV1Api
before(function() {
MockV1Api = MockV1ApiClass.instance()
})
const syncUserAndGetFeatures = function(user, callback) {
if (callback == null) {
callback = function(error, features) {}

View file

@ -14,8 +14,14 @@
const { expect } = require('chai')
const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
const MockV1HistoryApi = require('./helpers/MockV1HistoryApi')
const User = require('./helpers/User')
const MockV1HistoryApiClass = require('./mocks/MockV1HistoryApi')
let MockV1HistoryApi
before(function() {
MockV1HistoryApi = MockV1HistoryApiClass.instance()
})
describe('History', function() {
beforeEach(function(done) {
@ -94,9 +100,6 @@ describe('History', function() {
)
})
})
beforeEach(function resetCounter() {
MockV1HistoryApi.resetCounter()
})
it('should abort the upstream request', function(done) {
const request = this.owner.request(

View file

@ -1,24 +1,41 @@
const App = require('../../../app.js')
const { exec } = require('child_process')
const { waitForDb, db } = require('../../../app/src/infrastructure/mongodb')
const MongoHelper = require('./helpers/MongoHelper')
const { logger } = require('logger-sharelatex')
require('logger-sharelatex').logger.level('error')
const MockAnalyticsApi = require('./mocks/MockAnalyticsApi')
const MockChatApi = require('./mocks/MockChatApi')
const MockClsiApi = require('./mocks/MockClsiApi')
const MockDocstoreApi = require('./mocks/MockDocstoreApi')
const MockDocUpdaterApi = require('./mocks/MockDocUpdaterApi')
const MockFilestoreApi = require('./mocks/MockFilestoreApi')
const MockNotificationsApi = require('./mocks/MockNotificationsApi')
const MockProjectHistoryApi = require('./mocks/MockProjectHistoryApi')
const MockRecurlyApi = require('./mocks/MockRecurlyApi')
const MockSpellingApi = require('./mocks/MockSpellingApi')
const MockV1Api = require('./mocks/MockV1Api')
const MockV1HistoryApi = require('./mocks/MockV1HistoryApi')
before(waitForDb)
logger.level('error')
MongoHelper.initialize()
const mockOpts = {
debug: ['1', 'true', 'TRUE'].includes(process.env.DEBUG_MOCKS)
}
MockAnalyticsApi.initialize(3050, mockOpts)
MockChatApi.initialize(3010, mockOpts)
MockClsiApi.initialize(3013, mockOpts)
MockDocstoreApi.initialize(3016, mockOpts)
MockDocUpdaterApi.initialize(3003, mockOpts)
MockFilestoreApi.initialize(3009, mockOpts)
MockNotificationsApi.initialize(3042, mockOpts)
MockProjectHistoryApi.initialize(3054, mockOpts)
MockRecurlyApi.initialize(6034, mockOpts)
MockSpellingApi.initialize(3005, mockOpts)
MockV1Api.initialize(5000, mockOpts)
MockV1HistoryApi.initialize(3100, mockOpts)
before(function(done) {
exec('bin/east migrate', (error, stdout, stderr) => {
console.log(stdout)
console.error(stderr)
if (error) {
throw error
}
App.listen(3000, 'localhost', done)
})
})
afterEach(async function() {
return Promise.all(
Object.values(db).map(collection => collection.deleteMany({}))
)
App.listen(3000, 'localhost', done)
})

View file

@ -16,8 +16,14 @@ const { expect } = require('chai')
const { ObjectId } = require('mongodb')
const request = require('./helpers/request')
const MockProjectHistoryApi = require('./helpers/MockProjectHistoryApi')
const User = require('./helpers/User')
const MockProjectHistoryApiClass = require('./mocks/MockProjectHistoryApi')
let MockProjectHistoryApi
before(function() {
MockProjectHistoryApi = MockProjectHistoryApiClass.instance()
})
describe('Labels', function() {
beforeEach(function(done) {
@ -40,10 +46,6 @@ describe('Labels', function() {
})
})
afterEach(function() {
return MockProjectHistoryApi.reset()
})
it('getting labels', function(done) {
const label_id = new ObjectId().toString()
const comment = 'a label comment'

View file

@ -5,8 +5,6 @@ const { promisify } = require('util')
const Settings = require('settings-sharelatex')
const User = require('./helpers/User').promises
require('./helpers/MockFileStoreApi')
require('./helpers/MockClsiApi')
const express = require('express')
const LinkedUrlProxy = express()

View file

@ -26,11 +26,19 @@ const _ = require('underscore')
const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
const MockDocStoreApi = require('./helpers/MockDocstoreApi')
const MockFileStoreApi = require('./helpers/MockFileStoreApi')
const request = require('./helpers/request')
const User = require('./helpers/User')
const MockDocstoreApiClass = require('./mocks/MockDocstoreApi')
const MockFilestoreApiClass = require('./mocks/MockFilestoreApi')
let MockDocstoreApi, MockFilestoreApi
before(function() {
MockDocstoreApi = MockDocstoreApiClass.instance()
MockFilestoreApi = MockFilestoreApiClass.instance()
})
describe('ProjectDuplicateNames', function() {
beforeEach(function(done) {
this.owner = new User()
@ -89,12 +97,12 @@ describe('ProjectDuplicateNames', function() {
})
it('should create two docs in the docstore', function() {
const docs = MockDocStoreApi.docs[this.example_project_id]
const docs = MockDocstoreApi.docs[this.example_project_id]
return expect(Object.keys(docs).length).to.equal(2)
})
it('should create one file in the filestore', function() {
const files = MockFileStoreApi.files[this.example_project_id]
const files = MockFilestoreApi.files[this.example_project_id]
return expect(Object.keys(files).length).to.equal(1)
})

View file

@ -9,10 +9,14 @@ const _ = require('underscore')
const { Project } = require('../../../app/src/models/Project')
const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
const MockDocUpdaterApi = require('./helpers/MockDocUpdaterApi')
require('./helpers/MockFileStoreApi')
require('./helpers/MockProjectHistoryApi')
const User = require('./helpers/User')
const MockDocUpdaterApiClass = require('./mocks/MockDocUpdaterApi')
let MockDocUpdaterApi
before(function() {
MockDocUpdaterApi = MockDocUpdaterApiClass.instance()
})
describe('ProjectStructureChanges', function() {
let owner
@ -183,7 +187,6 @@ describe('ProjectStructureChanges', function() {
let exampleProjectId
beforeEach(function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates()
createExampleProject(owner, (err, projectId) => {
exampleProjectId = projectId
done(err)
@ -216,7 +219,6 @@ describe('ProjectStructureChanges', function() {
let dupProjectId
beforeEach(function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates()
createExampleProject(owner, (err, projectId) => {
if (err) {
return done(err)
@ -273,7 +275,7 @@ describe('ProjectStructureChanges', function() {
return done(err)
}
exampleProjectId = projectId
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
ProjectGetter.getProject(projectId, (error, project) => {
if (error) {
@ -557,7 +559,7 @@ describe('ProjectStructureChanges', function() {
}
exampleProjectId = projectId
rootFolderId = folderId
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
ProjectGetter.getProject(projectId, (error, project) => {
if (error) {
throw error
@ -586,7 +588,7 @@ describe('ProjectStructureChanges', function() {
})
it('should version a replacement file', function(done) {
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
uploadFile(
owner,
@ -657,7 +659,7 @@ describe('ProjectStructureChanges', function() {
throw error
}
oldVersion = project.version
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
done()
})
})
@ -736,7 +738,7 @@ describe('ProjectStructureChanges', function() {
exampleDocId,
exampleFolderId,
() => {
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
owner.request.post(
{
@ -818,7 +820,7 @@ describe('ProjectStructureChanges', function() {
exampleFolderId = folderId
moveItem(owner, projectId, 'doc', docId, folderId, () => {
moveItem(owner, projectId, 'file', fileId, folderId, () => {
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
ProjectGetter.getProject(
exampleProjectId,
(error, project) => {
@ -955,7 +957,7 @@ describe('ProjectStructureChanges', function() {
}
moveItem(owner, projectId, 'doc', docId, folderId, () => {
moveItem(owner, projectId, 'file', fileId, folderId, () => {
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
ProjectGetter.getProject(
exampleProjectId,
(error, project) => {
@ -1012,7 +1014,7 @@ describe('ProjectStructureChanges', function() {
return done(err)
}
this.exampleDocId = docId
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
ProjectGetter.getProject(
this.exampleProjectId,
(error, project) => {
@ -1109,7 +1111,7 @@ describe('ProjectStructureChanges', function() {
if (error) {
throw error
}
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
rootFolderId = project.rootFolder[0]._id.toString()
oldVersion = project.version
done()
@ -1214,7 +1216,7 @@ describe('ProjectStructureChanges', function() {
if (error) {
throw error
}
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
oldVersion = project.version
done()
})
@ -1326,7 +1328,7 @@ describe('ProjectStructureChanges', function() {
}
exampleProjectId = projectId
rootFolderId = folderId
MockDocUpdaterApi.clearProjectStructureUpdates()
MockDocUpdaterApi.reset()
done()
})
})

View file

@ -13,7 +13,6 @@ const should = require('chai').should()
const { assert } = require('chai')
const async = require('async')
const request = require('./helpers/request')
const MockV1Api = require('./helpers/MockV1Api')
const assertResponse = (path, expectedStatusCode, expectedBody, cb) =>
request.get(path, (error, response) => {

View file

@ -2,7 +2,6 @@ const { expect } = require('chai')
const async = require('async')
const User = require('./helpers/User')
const RecurlySubscription = require('./helpers/RecurlySubscription')
require('./helpers/MockV1Api')
describe('Subscriptions', function() {
describe('update', function() {

View file

@ -13,7 +13,6 @@ const should = require('chai').should()
const { assert } = require('chai')
const async = require('async')
const request = require('./helpers/request')
const MockV1Api = require('./helpers/MockV1Api')
const assertRedirect = (method, path, expectedStatusCode, destination, cb) =>
request[method](path, (error, response) => {

View file

@ -20,9 +20,17 @@ const Path = require('path')
const ProjectGetter = require('../../../app/src/Features/Project/ProjectGetter.js')
const User = require('./helpers/User')
const MockProjectHistoryApi = require('./helpers/MockProjectHistoryApi')
const MockDocstoreApi = require('./helpers/MockDocstoreApi')
const MockFileStoreApi = require('./helpers/MockFileStoreApi')
const MockProjectHistoryApiClass = require('./mocks/MockProjectHistoryApi')
const MockDocstoreApiClass = require('./mocks/MockDocstoreApi')
const MockFilestoreApiClass = require('./mocks/MockFilestoreApi')
let MockProjectHistoryApi, MockDocstoreApi, MockFilestoreApi
before(function() {
MockProjectHistoryApi = MockProjectHistoryApiClass.instance()
MockDocstoreApi = MockDocstoreApiClass.instance()
MockFilestoreApi = MockFilestoreApiClass.instance()
})
describe('RestoringFiles', function() {
beforeEach(function(done) {
@ -193,7 +201,7 @@ describe('RestoringFiles', function() {
project.rootFolder[0].fileRefs,
file => file.name === 'image.png'
)
file = MockFileStoreApi.files[this.project_id][file._id]
file = MockFilestoreApi.files[this.project_id][file._id]
expect(file.content).to.equal(this.pngData)
return done()
})

View file

@ -11,7 +11,13 @@
const should = require('chai').should()
const async = require('async')
const User = require('./helpers/User')
const MockV1Api = require('./helpers/MockV1Api')
const MockV1ApiClass = require('./mocks/MockV1Api')
let MockV1Api
before(function() {
MockV1Api = MockV1ApiClass.instance()
})
describe('SettingsPage', function() {
beforeEach(function(done) {

View file

@ -17,9 +17,15 @@ const { Subscription } = require('../../../app/src/models/Subscription')
const { Institution } = require('../../../app/src/models/Institution')
const SubscriptionViewModelBuilder = require('../../../app/src/Features/Subscription/SubscriptionViewModelBuilder')
const RecurlySubscription = require('./helpers/RecurlySubscription')
const MockRecurlyApiClass = require('./mocks/MockRecurlyApi')
const MockV1ApiClass = require('./mocks/MockV1Api')
const MockRecurlyApi = require('./helpers/MockRecurlyApi')
const MockV1Api = require('./helpers/MockV1Api')
let MockV1Api, MockRecurlyApi
before(function() {
MockV1Api = MockV1ApiClass.instance()
MockRecurlyApi = MockRecurlyApiClass.instance()
})
describe('Subscriptions', function() {
describe('dashboard', function() {

View file

@ -4,7 +4,6 @@ const request = require('./helpers/request')
const User = require('./helpers/User')
const RecurlySubscription = require('./helpers/RecurlySubscription')
const SubscriptionUpdater = require('../../../app/src/Features/Subscription/SubscriptionUpdater')
require('./helpers/MockV1Api')
describe('Subscriptions', function() {
describe('deletion', function() {

View file

@ -1,13 +1,18 @@
const { expect } = require('chai')
const async = require('async')
const MockV1Api = require('./helpers/MockV1Api')
const User = require('./helpers/User')
const request = require('./helpers/request')
const settings = require('settings-sharelatex')
const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
const MockV1ApiClass = require('./mocks/MockV1Api')
const expectErrorResponse = require('./helpers/expectErrorResponse')
let MockV1Api
before(function() {
MockV1Api = MockV1ApiClass.instance()
})
const tryEditorAccess = (user, projectId, test, callback) =>
async.series(
[

View file

@ -6,9 +6,15 @@ const User = require('./helpers/User')
const UserHelper = require('./helpers/UserHelper')
const UserUpdater = require('../../../app/src/Features/User/UserUpdater')
const { db, ObjectId } = require('../../../app/src/infrastructure/mongodb')
const MockV1Api = require('./helpers/MockV1Api')
const MockV1ApiClass = require('./mocks/MockV1Api')
const expectErrorResponse = require('./helpers/expectErrorResponse')
let MockV1Api
before(function() {
MockV1Api = MockV1ApiClass.instance()
})
describe('UserEmails', function() {
beforeEach(function(done) {
this.timeout(20000)

View file

@ -1,26 +0,0 @@
let MockAnalyticsApi
const express = require('express')
const app = express()
module.exports = MockAnalyticsApi = {
updates: {},
run() {
app.get('/graphs/:graph', (req, res, next) => {
return res.json({})
})
app
.listen(3050, error => {
if (error) {
throw error
}
})
.on('error', error => {
console.error('error starting MockAnalyticsApi:', error.message)
return process.exit(1)
})
}
}
MockAnalyticsApi.run()

View file

@ -1,51 +0,0 @@
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const projects = {}
const MessageHttpController = {
getGlobalMessages: (req, res) => {
res.send(projects[req.params.project_id] || [])
},
sendGlobalMessage: (req, res) => {
const projectId = req.params.project_id
const message = {
id: Math.random().toString(),
content: req.body.content,
timestamp: Date.now(),
user_id: req.body.user_id
}
projects[projectId] = projects[projectId] || []
projects[projectId].push(message)
res.sendStatus(201).send(Object.assign({ room_id: projectId }, message))
}
}
const MockChatApi = {
run() {
app.use(bodyParser.json())
app.get(
'/project/:project_id/messages',
MessageHttpController.getGlobalMessages
)
app.post(
'/project/:project_id/messages',
MessageHttpController.sendGlobalMessage
)
app
.listen(3010, error => {
if (error) {
throw error
}
})
.on('error', error => {
console.error('error starting MockChatApi:', error.message)
return process.exit(1)
})
}
}
MockChatApi.run()

View file

@ -1,84 +0,0 @@
/* eslint-disable
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockClsiApi
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
module.exports = MockClsiApi = {
run() {
const compile = (req, res, next) => {
return res.status(200).send({
compile: {
status: 'success',
error: null,
outputFiles: [
{
url: `/project/${req.params.project_id}/build/1234/output/project.pdf`,
path: 'project.pdf',
type: 'pdf',
build: 1234
},
{
url: `/project/${req.params.project_id}/build/1234/output/project.log`,
path: 'project.log',
type: 'log',
build: 1234
}
]
}
})
}
app.post('/project/:project_id/compile', compile)
app.post('/project/:project_id/user/:user_id/compile', compile)
app.get(
'/project/:project_id/build/:build_id/output/*',
(req, res, next) => {
const filename = req.params[0]
if (filename === 'project.pdf') {
return res.status(200).send('mock-pdf')
} else if (filename === 'project.log') {
return res.status(200).send('mock-log')
} else {
return res.sendStatus(404)
}
}
)
app.get(
'/project/:project_id/user/:user_id/build/:build_id/output/:output_path',
(req, res, next) => {
return res.status(200).send('hello')
}
)
app.get('/project/:project_id/status', (req, res, next) => {
return res.status(200).send()
})
return app
.listen(3013, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockClsiApi:', error.message)
return process.exit(1)
})
}
}
MockClsiApi.run()

View file

@ -1,76 +0,0 @@
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
const MockDocUpdaterApi = {
updates: {},
clearProjectStructureUpdates() {
this.updates = {}
},
getProjectStructureUpdates(projectId) {
return this.updates[projectId] || { updates: [] }
},
addProjectStructureUpdates(projectId, userId, updates, version) {
if (!this.updates[projectId]) {
this.updates[projectId] = { updates: [] }
}
for (const update of updates) {
update.userId = userId
this.updates[projectId].updates.push(update)
}
this.updates[projectId].version = version
},
run() {
app.post('/project/:projectId/flush', (req, res, next) => {
res.sendStatus(204)
})
app.post('/project/:projectId', jsonParser, (req, res, next) => {
const { projectId } = req.params
const { userId, updates, version } = req.body
this.addProjectStructureUpdates(projectId, userId, updates, version)
res.sendStatus(200)
})
app.post('/project/:projectId/doc/:doc_id', (req, res, next) => {
res.sendStatus(204)
})
app.delete('/project/:projectId', (req, res) => {
res.sendStatus(204)
})
app.post('/project/:projectId/doc/:doc_id/flush', (req, res, next) => {
res.sendStatus(204)
})
app.delete('/project/:projectId/doc/:doc_id', (req, res, next) => {
res.sendStatus(204)
})
app.post('/project/:projectId/history/resync', (req, res, next) => {
res.sendStatus(204)
})
app
.listen(3003, error => {
if (error) {
throw error
}
})
.on('error', error => {
console.error('error starting MockDocUpdaterApi:', error.message)
process.exit(1)
})
}
}
MockDocUpdaterApi.run()
module.exports = MockDocUpdaterApi

View file

@ -1,111 +0,0 @@
/* eslint-disable
camelcase,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockDocStoreApi
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
module.exports = MockDocStoreApi = {
docs: {},
run() {
app.post(
'/project/:project_id/doc/:doc_id',
bodyParser.json(),
(req, res, next) => {
const { project_id, doc_id } = req.params
const { lines, version, ranges } = req.body
if (this.docs[project_id] == null) {
this.docs[project_id] = {}
}
if (this.docs[project_id][doc_id] == null) {
this.docs[project_id][doc_id] = {}
}
const { version: oldVersion, deleted } = this.docs[project_id][doc_id]
this.docs[project_id][doc_id] = { lines, version, ranges, deleted }
if (this.docs[project_id][doc_id].rev == null) {
this.docs[project_id][doc_id].rev = 0
}
this.docs[project_id][doc_id].rev += 1
this.docs[project_id][doc_id]._id = doc_id
return res.json({
modified: oldVersion !== version,
rev: this.docs[project_id][doc_id].rev
})
}
)
app.get('/project/:project_id/doc', (req, res, next) => {
const docs = (() => {
const result = []
for (let doc_id in this.docs[req.params.project_id]) {
const doc = this.docs[req.params.project_id][doc_id]
result.push(doc)
}
return result
})()
return res.json(docs)
})
app.get('/project/:project_id/doc/:doc_id', (req, res, next) => {
const { project_id, doc_id } = req.params
const doc = this.docs[project_id][doc_id]
if (doc == null || (doc.deleted && !req.query.include_deleted)) {
return res.sendStatus(404)
} else {
return res.json(doc)
}
})
app.get('/project/:project_id/doc/:doc_id/deleted', (req, res) => {
const { project_id, doc_id } = req.params
if (!this.docs[project_id] || !this.docs[project_id][doc_id]) {
res.sendStatus(404)
} else {
res.json({ deleted: Boolean(this.docs[project_id][doc_id].deleted) })
}
})
app.delete('/project/:project_id/doc/:doc_id', (req, res, next) => {
const { project_id, doc_id } = req.params
if (this.docs[project_id] == null) {
return res.sendStatus(404)
} else if (this.docs[project_id][doc_id] == null) {
return res.sendStatus(404)
} else {
this.docs[project_id][doc_id].deleted = true
return res.sendStatus(204)
}
})
app.post('/project/:project_id/destroy', (req, res, next) => {
const { project_id } = req.params
delete this.docs[project_id]
res.sendStatus(204)
})
return app
.listen(3016, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockDocStoreApi:', error.message)
return process.exit(1)
})
}
}
MockDocStoreApi.run()

View file

@ -1,85 +0,0 @@
/* eslint-disable
camelcase,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockFileStoreApi
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
module.exports = MockFileStoreApi = {
files: {},
run() {
app.post('/project/:project_id/file/:file_id', (req, res, next) => {
const chunks = []
req.on('data', chunk => chunks.push(chunk))
return req.on('end', () => {
const content = Buffer.concat(chunks).toString()
const { project_id, file_id } = req.params
if (this.files[project_id] == null) {
this.files[project_id] = {}
}
this.files[project_id][file_id] = { content }
return res.sendStatus(200)
})
})
app.get('/project/:project_id/file/:file_id', (req, res, next) => {
const { project_id, file_id } = req.params
const { content } = this.files[project_id][file_id]
return res.send(content)
})
// handle file copying
app.put(
'/project/:project_id/file/:file_id',
bodyParser.json(),
(req, res, next) => {
const { project_id, file_id } = req.params
const { source } = req.body
const { content } =
this.files[source.project_id] != null
? this.files[source.project_id][source.file_id]
: undefined
if (content == null) {
return res.sendStatus(500)
} else {
if (this.files[project_id] == null) {
this.files[project_id] = {}
}
this.files[project_id][file_id] = { content }
return res.sendStatus(200)
}
}
)
app.delete('/project/:projectId', (req, res) => {
const { projectId } = req.params
delete this.files[projectId]
res.sendStatus(204)
})
return app
.listen(3009, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockFileStoreApi:', error.message)
return process.exit(1)
})
}
}
MockFileStoreApi.run()

View file

@ -0,0 +1,25 @@
const { exec } = require('child_process')
const { waitForDb, db } = require('../../../../app/src/infrastructure/mongodb')
module.exports = {
initialize() {
before(waitForDb)
before(function(done) {
exec('bin/east migrate', (error, stdout, stderr) => {
console.log(stdout)
console.error(stderr)
if (error) {
throw error
}
done()
})
})
afterEach(async function() {
return Promise.all(
Object.values(db).map(collection => collection.deleteMany({}))
)
})
}
}

View file

@ -1,8 +1,14 @@
const { ObjectId } = require('mongodb')
const Subscription = require('./Subscription')
const MockRecurlyApi = require('./MockRecurlyApi')
const MockRecurlyApiClass = require('../mocks/MockRecurlyApi')
const RecurlyWrapper = require('../../../../app/src/Features/Subscription/RecurlyWrapper')
let MockRecurlyApi
before(function() {
MockRecurlyApi = MockRecurlyApiClass.instance()
})
class RecurlySubscription {
constructor(options = {}) {
options.recurlySubscription_id = ObjectId().toString()

View file

@ -0,0 +1,198 @@
const OError = require('@overleaf/o-error')
const express = require('express')
const bodyParser = require('body-parser')
/**
* Abstract class for running a mock API via Express. Handles setting up of
* the server on a specific port, and provides an overridable method to
* initialise routes.
*
* Mocks are singletons, and must be initialized with the `initialize` method.
* Instance objects are available via the `instance()` method.
*
* You must override 'reset' and 'applyRoutes' when subclassing this
*
* Wraps the express app's http verb methods for convenience
*
* @hideconstructor
* @member {number} port - the port for the http server
* @member app - the Express application
*/
class AbstractMockApi {
/**
* Create a new API. No not call directly - use the `initialize` method
*
* @param {number} port - The TCP port to start the API on
* @param {object} options - An optional hash of options to modify the behaviour of the mock
* @param {boolean} options.debug - When true, print http requests and responses to stdout
* Set this to 'true' from the constructor of your derived class
*/
constructor(port, { debug } = {}) {
if (!this.constructor._fromInit) {
throw new OError(
'do not create this class directly - use the initialize method',
{ className: this.constructor.name }
)
}
if (this.constructor._obj) {
throw new OError('mock already initialized', {
className: this.constructor._obj.constructor.name,
port: this.port
})
}
if (this.constructor === AbstractMockApi) {
throw new OError(
'Do not construct AbstractMockApi directly - use a subclass'
)
}
this.debug = debug
this.port = port
this.app = express()
this.app.use(bodyParser.json())
this.app.use(bodyParser.urlencoded({ extended: true }))
}
/**
* Apply debugging routes to print out API activity to stdout
*/
applyDebugRoutes() {
if (!this.debug) return
this.app.use((req, res, next) => {
const { method, path, query, params, body } = req
// eslint-disable-next-line no-console
console.log(`${this.constructor.name} REQUEST`, {
method,
path,
query,
params,
body
})
const oldEnd = res.end
const oldJson = res.json
res.json = (...args) => {
// eslint-disable-next-line no-console
console.log(`${this.constructor.name} RESPONSE JSON`, args[0])
oldJson.call(res, ...args)
}
res.end = (...args) => {
// eslint-disable-next-line no-console
console.log(`${this.constructor.name} STATUS`, res.statusCode)
if (res.statusCode >= 500) {
// eslint-disable-next-line no-console
console.log('ERROR RESPONSE:', args)
}
oldEnd.call(res, ...args)
}
next()
})
}
/**
* Overridable method to add routes - should be overridden in derived classes
* @abstract
*/
applyRoutes() {
throw new OError(
'AbstractMockApi base class implementation should not be called'
)
}
/**
* Resets member data and restores the API to a clean state for the next test run
* - should be overridden in derived classes
* @abstract
*/
reset() {
throw new OError(
'AbstractMockApi base class implementation should not be called'
)
}
/**
* Applies mocha hooks to start and stop the API at the beginning/end of
* the test suite, and reset before each test run
*
* @param {number} port - The TCP port to start the API on
* @param {object} options - An optional hash of options to modify the behaviour of the mock
* @param {boolean} options.debug - When true, print http requests and responses to stdout
* Set this to 'true' from the constructor of your derived class
*/
static initialize(port, { debug } = {}) {
// `this` refers to the derived class
this._fromInit = true
this._obj = new this(port, { debug })
this._obj.applyDebugRoutes()
this._obj.applyRoutes()
/* eslint-disable mocha/no-mocha-arrows */
const name = this.constructor.name
before(`starting mock ${name}`, () => this._obj.start())
after(`stopping mock ${name}`, () => this._obj.stop())
beforeEach(`resetting mock ${name}`, () => this._obj.reset())
}
/**
* Starts the API on the configured port
*
* @return {Promise<void>}
*/
async start() {
return new Promise((resolve, reject) => {
if (this.debug) {
// eslint-disable-next-line no-console
console.log('Starting mock on port', this.constructor.name, this.port)
}
this.server = this.app
.listen(this.port, err => {
if (err) {
return reject(err)
}
resolve()
})
.on('error', error => {
// eslint-disable-next-line no-console
console.error(
'error starting mock:',
this.constructor.name,
error.message
)
process.exit(1)
})
})
}
/**
* Returns the constructed object
*
* @return {AbstractMockApi}
*/
static instance() {
return this._obj
}
/**
* Shuts down the API and waits for it to stop listening
*
* @return {Promise<void>}
*/
async stop() {
if (!this.server) return
return new Promise((resolve, reject) => {
if (this.debug) {
// eslint-disable-next-line no-console
console.log('Stopping mock', this.constructor.name)
}
this.server.close(err => {
delete this.server
if (err) {
return reject(err)
}
resolve()
})
})
}
}
module.exports = AbstractMockApi

View file

@ -0,0 +1,41 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockAnalyticsApi extends AbstractMockApi {
reset() {
this.updates = {}
}
applyRoutes() {
this.app.get('/graphs/:graph', (req, res) => {
return res.json({})
})
this.app.get('/recentInstitutionActivity', (req, res) => {
res.json({
institutionId: 123,
day: {
projects: 0,
users: 0
},
week: {
projects: 0,
users: 0
},
month: {
projects: 1,
users: 2
}
})
})
}
}
module.exports = MockAnalyticsApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockAnalyticsApi
* @static
* @returns {MockAnalyticsApi}
*/

View file

@ -0,0 +1,43 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockChatApi extends AbstractMockApi {
reset() {
this.projects = {}
}
getGlobalMessages(req, res) {
res.send(this.projects[req.params.project_id] || [])
}
sendGlobalMessage(req, res) {
const projectId = req.params.project_id
const message = {
id: Math.random().toString(),
content: req.body.content,
timestamp: Date.now(),
user_id: req.body.user_id
}
this.projects[projectId] = this.projects[projectId] || []
this.projects[projectId].push(message)
res.sendStatus(201).send(Object.assign({ room_id: projectId }, message))
}
applyRoutes() {
this.app.get('/project/:project_id/messages', (req, res) =>
this.getGlobalMessages(req, res)
)
this.app.post('/project/:project_id/messages', (req, res) =>
this.sendGlobalMessage(req, res)
)
}
}
module.exports = MockChatApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockChatApi
* @static
* @returns {MockChatApi}
*/

View file

@ -0,0 +1,71 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockClsiApi extends AbstractMockApi {
reset() {}
static compile(req, res) {
res.status(200).send({
compile: {
status: 'success',
error: null,
outputFiles: [
{
url: `/project/${req.params.project_id}/build/1234/output/project.pdf`,
path: 'project.pdf',
type: 'pdf',
build: 1234
},
{
url: `/project/${req.params.project_id}/build/1234/output/project.log`,
path: 'project.log',
type: 'log',
build: 1234
}
]
}
})
}
applyRoutes() {
this.app.post('/project/:project_id/compile', MockClsiApi.compile)
this.app.post(
'/project/:project_id/user/:user_id/compile',
MockClsiApi.compile
)
this.app.get(
'/project/:project_id/build/:build_id/output/*',
(req, res) => {
const filename = req.params[0]
if (filename === 'project.pdf') {
res.status(200).send('mock-pdf')
} else if (filename === 'project.log') {
res.status(200).send('mock-log')
} else {
res.sendStatus(404)
}
}
)
this.app.get(
'/project/:project_id/user/:user_id/build/:build_id/output/:output_path',
(req, res) => {
res.status(200).send('hello')
}
)
this.app.get('/project/:project_id/status', (req, res) => {
res.status(200).send()
})
}
}
module.exports = MockClsiApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockClsiApi
* @static
* @returns {MockClsiApi}
*/

View file

@ -0,0 +1,67 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockDocUpdaterApi extends AbstractMockApi {
reset() {
this.updates = {}
}
getProjectStructureUpdates(projectId) {
return this.updates[projectId] || { updates: [] }
}
addProjectStructureUpdates(projectId, userId, updates, version) {
if (!this.updates[projectId]) {
this.updates[projectId] = { updates: [] }
}
for (const update of updates) {
update.userId = userId
this.updates[projectId].updates.push(update)
}
this.updates[projectId].version = version
}
applyRoutes() {
this.app.post('/project/:projectId/flush', (req, res) => {
res.sendStatus(204)
})
this.app.post('/project/:projectId', (req, res) => {
const { projectId } = req.params
const { userId, updates, version } = req.body
this.addProjectStructureUpdates(projectId, userId, updates, version)
res.sendStatus(200)
})
this.app.post('/project/:projectId/doc/:doc_id', (req, res) => {
res.sendStatus(204)
})
this.app.delete('/project/:projectId', (req, res) => {
res.sendStatus(204)
})
this.app.post('/project/:projectId/doc/:doc_id/flush', (req, res) => {
res.sendStatus(204)
})
this.app.delete('/project/:projectId/doc/:doc_id', (req, res) => {
res.sendStatus(204)
})
this.app.post('/project/:projectId/history/resync', (req, res) => {
res.sendStatus(204)
})
}
}
module.exports = MockDocUpdaterApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockDocUpdaterApi
* @static
* @returns {MockDocUpdaterApi}
*/

View file

@ -0,0 +1,82 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockDocstoreApi extends AbstractMockApi {
reset() {
this.docs = {}
}
applyRoutes() {
this.app.post('/project/:projectId/doc/:docId', (req, res) => {
const { projectId, docId } = req.params
const { lines, version, ranges } = req.body
if (this.docs[projectId] == null) {
this.docs[projectId] = {}
}
if (this.docs[projectId][docId] == null) {
this.docs[projectId][docId] = {}
}
const { version: oldVersion, deleted } = this.docs[projectId][docId]
this.docs[projectId][docId] = { lines, version, ranges, deleted }
if (this.docs[projectId][docId].rev == null) {
this.docs[projectId][docId].rev = 0
}
this.docs[projectId][docId].rev += 1
this.docs[projectId][docId]._id = docId
res.json({
modified: oldVersion !== version,
rev: this.docs[projectId][docId].rev
})
})
this.app.get('/project/:projectId/doc', (req, res) => {
res.json(Object.values(this.docs[req.params.projectId] || {}))
})
this.app.get('/project/:projectId/doc/:docId', (req, res) => {
const { projectId, docId } = req.params
const doc = this.docs[projectId][docId]
if (!doc || (doc.deleted && !req.query.include_deleted)) {
res.sendStatus(404)
} else {
res.json(doc)
}
})
this.app.get('/project/:projectId/doc/:docId/deleted', (req, res) => {
const { projectId, docId } = req.params
if (!this.docs[projectId] || !this.docs[projectId][docId]) {
res.sendStatus(404)
} else {
res.json({ deleted: Boolean(this.docs[projectId][docId].deleted) })
}
})
this.app.delete('/project/:projectId/doc/:docId', (req, res) => {
const { projectId, docId } = req.params
if (!this.docs[projectId]) {
res.sendStatus(404)
} else if (!this.docs[projectId][docId]) {
res.sendStatus(404)
} else {
this.docs[projectId][docId].deleted = true
res.sendStatus(204)
}
})
this.app.post('/project/:projectId/destroy', (req, res) => {
const { projectId } = req.params
delete this.docs[projectId]
res.sendStatus(204)
})
}
}
module.exports = MockDocstoreApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockDocstoreApi
* @static
* @returns {MockDocstoreApi}
*/

View file

@ -0,0 +1,64 @@
const AbstractMockApi = require('./AbstractMockApi')
class MockFilestoreApi extends AbstractMockApi {
reset() {
this.files = {}
}
applyRoutes() {
this.app.post('/project/:projectId/file/:fileId', (req, res) => {
const chunks = []
req.on('data', chunk => chunks.push(chunk))
req.on('end', () => {
const content = Buffer.concat(chunks).toString()
const { projectId, fileId } = req.params
if (!this.files[projectId]) {
this.files[projectId] = {}
}
this.files[projectId][fileId] = { content }
res.sendStatus(200)
})
})
this.app.get('/project/:projectId/file/:fileId', (req, res) => {
const { projectId, fileId } = req.params
const { content } = this.files[projectId][fileId]
res.send(content)
})
// handle file copying
this.app.put('/project/:projectId/file/:fileId', (req, res) => {
const { projectId, fileId } = req.params
const { source } = req.body
const { content } =
this.files[source.project_id] &&
this.files[source.project_id][source.file_id]
if (!content) {
res.sendStatus(500)
} else {
if (!this.files[projectId]) {
this.files[projectId] = {}
}
this.files[projectId][fileId] = { content }
res.sendStatus(200)
}
})
this.app.delete('/project/:projectId', (req, res) => {
const { projectId } = req.params
delete this.files[projectId]
res.sendStatus(204)
})
}
}
module.exports = MockFilestoreApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockFilestoreApi
* @static
* @returns {MockFilestoreApi}
*/

View file

@ -0,0 +1,24 @@
const AbstractMockApi = require('./AbstractMockApi')
// Currently there is nothing implemented here as we have no acceptance tests
// for the notifications API. This does however stop errors appearing in the
// output when the acceptance tests try to connect.
class MockNotificationsApi extends AbstractMockApi {
reset() {}
applyRoutes() {
this.app.get('/*', (req, res) => res.sendStatus(200))
this.app.post('/*', (req, res) => res.sendStatus(200))
}
}
module.exports = MockNotificationsApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockNotificationsApi
* @static
* @returns {MockNotificationsApi}
*/

View file

@ -1,36 +1,32 @@
let MockProjectHistoryApi
const AbstractMockApi = require('./AbstractMockApi')
const _ = require('lodash')
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const { ObjectId } = require('mongodb')
module.exports = MockProjectHistoryApi = {
docs: {},
oldFiles: {},
projectVersions: {},
labels: {},
projectSnapshots: {},
class MockProjectHistoryApi extends AbstractMockApi {
reset() {
this.docs = {}
this.oldFiles = {}
this.projectVersions = {}
this.labels = {}
this.projectSnapshots = {}
this.projectHistoryId = 1
}
addOldFile(projectId, version, pathname, content) {
this.oldFiles[`${projectId}:${version}:${pathname}`] = content
},
}
addProjectSnapshot(projectId, version, snapshot) {
this.projectSnapshots[`${projectId}:${version}`] = snapshot
},
}
setProjectVersion(projectId, version) {
this.projectVersions[projectId] = { version }
},
}
setProjectVersionInfo(projectId, versionInfo) {
this.projectVersions[projectId] = versionInfo
},
}
addLabel(projectId, label) {
if (label.id == null) {
@ -40,40 +36,31 @@ module.exports = MockProjectHistoryApi = {
this.labels[projectId] = {}
}
this.labels[projectId][label.id] = label
},
}
deleteLabel(projectId, labelId) {
delete this.labels[projectId][labelId]
},
}
getLabels(projectId) {
if (this.labels[projectId] == null) {
return null
}
return _.values(this.labels[projectId])
},
}
reset() {
this.oldFiles = {}
this.projectHistoryId = 1
this.projectVersions = {}
this.labels = {}
},
run() {
this.reset()
app.post('/project', (req, res, next) => {
applyRoutes() {
this.app.post('/project', (req, res) => {
res.json({ project: { id: this.projectHistoryId++ } })
})
app.delete('/project/:projectId', (req, res, next) => {
this.app.delete('/project/:projectId', (req, res) => {
res.sendStatus(204)
})
app.get(
this.app.get(
'/project/:projectId/version/:version/:pathname',
(req, res, next) => {
(req, res) => {
const { projectId, version, pathname } = req.params
const key = `${projectId}:${version}:${pathname}`
if (this.oldFiles[key] != null) {
@ -84,7 +71,7 @@ module.exports = MockProjectHistoryApi = {
}
)
app.get('/project/:projectId/version/:version', (req, res, next) => {
this.app.get('/project/:projectId/version/:version', (req, res) => {
const { projectId, version } = req.params
const key = `${projectId}:${version}`
if (this.projectSnapshots[key] != null) {
@ -94,7 +81,7 @@ module.exports = MockProjectHistoryApi = {
}
})
app.get('/project/:projectId/version', (req, res, next) => {
this.app.get('/project/:projectId/version', (req, res) => {
const { projectId } = req.params
if (this.projectVersions[projectId] != null) {
res.json(this.projectVersions[projectId])
@ -103,7 +90,7 @@ module.exports = MockProjectHistoryApi = {
}
})
app.get('/project/:projectId/labels', (req, res, next) => {
this.app.get('/project/:projectId/labels', (req, res) => {
const { projectId } = req.params
const labels = this.getLabels(projectId)
if (labels != null) {
@ -113,21 +100,17 @@ module.exports = MockProjectHistoryApi = {
}
})
app.post(
'/project/:projectId/user/:user_id/labels',
bodyParser.json(),
(req, res, next) => {
const { projectId } = req.params
const { comment, version } = req.body
const labelId = new ObjectId().toString()
this.addLabel(projectId, { id: labelId, comment, version })
res.json({ label_id: labelId, comment, version })
}
)
this.app.post('/project/:projectId/user/:user_id/labels', (req, res) => {
const { projectId } = req.params
const { comment, version } = req.body
const labelId = new ObjectId().toString()
this.addLabel(projectId, { id: labelId, comment, version })
res.json({ label_id: labelId, comment, version })
})
app.delete(
this.app.delete(
'/project/:projectId/user/:user_id/labels/:labelId',
(req, res, next) => {
(req, res) => {
const { projectId, labelId } = req.params
const label =
this.labels[projectId] != null
@ -142,21 +125,18 @@ module.exports = MockProjectHistoryApi = {
}
)
app.post('/project/:projectId/flush', (req, res, next) => {
this.app.post('/project/:projectId/flush', (req, res) => {
res.sendStatus(200)
})
app
.listen(3054, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockProjectHistoryApi:', error.message)
process.exit(1)
})
}
}
MockProjectHistoryApi.run()
module.exports = MockProjectHistoryApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockProjectHistoryApi
* @static
* @returns {MockProjectHistoryApi}
*/

View file

@ -1,53 +1,36 @@
/* eslint-disable
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockRecurlyApi
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const AbstractMockApi = require('./AbstractMockApi')
const SubscriptionController = require('../../../../app/src/Features/Subscription/SubscriptionController')
app.use(bodyParser.json())
module.exports = MockRecurlyApi = {
mockSubscriptions: [],
redemptions: {},
coupons: {},
class MockRecurlyApi extends AbstractMockApi {
reset() {
this.mockSubscriptions = []
this.redemptions = {}
this.coupons = {}
}
addMockSubscription(recurlySubscription) {
this.mockSubscriptions.push(recurlySubscription)
},
}
getMockSubscriptionByAccountId(accountId) {
return this.mockSubscriptions.find(
mockSubscription => mockSubscription.account.id === accountId
)
},
}
getMockSubscriptionById(uuid) {
return this.mockSubscriptions.find(
mockSubscription => mockSubscription.uuid === uuid
)
},
}
run() {
app.get('/subscriptions/:id', (req, res, next) => {
applyRoutes() {
this.app.get('/subscriptions/:id', (req, res) => {
const subscription = this.getMockSubscriptionById(req.params.id)
if (subscription == null) {
return res.status(404).end()
if (!subscription) {
res.status(404).end()
} else {
return res.send(`\
res.send(`\
<subscription>
<plan_code>${subscription.plan_code}</plan_code>
<currency>${subscription.currency}</currency>
@ -63,12 +46,12 @@ module.exports = MockRecurlyApi = {
}
})
app.get('/accounts/:id', (req, res, next) => {
this.app.get('/accounts/:id', (req, res) => {
const subscription = this.getMockSubscriptionByAccountId(req.params.id)
if (subscription == null) {
return res.status(404).end()
if (!subscription) {
res.status(404).end()
} else {
return res.send(`\
res.send(`\
<account>
<account_code>${req.params.id}</account_code>
<hosted_login_token>${subscription.account.hosted_login_token}</hosted_login_token>
@ -78,16 +61,16 @@ module.exports = MockRecurlyApi = {
}
})
app.put(
this.app.put(
'/accounts/:id',
SubscriptionController.recurlyNotificationParser, // required to parse XML requests
(req, res, next) => {
(req, res) => {
const subscription = this.getMockSubscriptionByAccountId(req.params.id)
if (subscription == null) {
return res.status(404).end()
if (!subscription) {
res.status(404).end()
} else {
Object.assign(subscription.account, req.body.account)
return res.send(`\
res.send(`\
<account>
<account_code>${req.params.id}</account_code>
<email>${subscription.account.email}</email>
@ -97,12 +80,12 @@ module.exports = MockRecurlyApi = {
}
)
app.get('/coupons/:code', (req, res, next) => {
this.app.get('/coupons/:code', (req, res) => {
const coupon = this.coupons[req.params.code]
if (coupon == null) {
return res.status(404).end()
if (!coupon) {
res.status(404).end()
} else {
return res.send(`\
res.send(`\
<coupon>
<coupon_code>${req.params.code}</coupon_code>
<name>${coupon.name || ''}</name>
@ -112,7 +95,7 @@ module.exports = MockRecurlyApi = {
}
})
app.get('/accounts/:id/redemptions', (req, res, next) => {
this.app.get('/accounts/:id/redemptions', (req, res) => {
const redemptions = this.redemptions[req.params.id] || []
let redemptionsListXml = ''
for (let redemption of Array.from(redemptions)) {
@ -124,19 +107,21 @@ module.exports = MockRecurlyApi = {
`
}
return res.send(`\
res.send(`\
<redemptions type="array">
${redemptionsListXml}
</redemptions>\
`)
})
return app.listen(6034, error => {
if (error != null) {
throw error
}
})
}
}
MockRecurlyApi.run()
module.exports = MockRecurlyApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockRecurlyApi
* @static
* @returns {MockRecurlyApi}
*/

View file

@ -1,23 +1,24 @@
const express = require('express')
const app = express()
const AbstractMockApi = require('./AbstractMockApi')
const MockSpellingApi = {
words: {},
class MockSpellingApi extends AbstractMockApi {
reset() {
this.words = {}
}
run() {
app.get('/user/:userId', (req, res) => {
applyRoutes() {
this.app.get('/user/:userId', (req, res) => {
const { userId } = req.params
const words = this.words[userId] || []
res.json(words)
})
app.delete('/user/:userId', (req, res) => {
this.app.delete('/user/:userId', (req, res) => {
const { userId } = req.params
this.words.delete(userId)
res.sendStatus(200)
})
app.post('/user/:userId/learn', (req, res) => {
this.app.post('/user/:userId/learn', (req, res) => {
const word = req.body.word
const { userId } = req.params
if (word) {
@ -29,7 +30,7 @@ const MockSpellingApi = {
res.sendStatus(200)
})
app.post('/user/:userId/unlearn', (req, res) => {
this.app.post('/user/:userId/unlearn', (req, res) => {
const word = req.body.word
const { userId } = req.params
if (word && this.words[userId]) {
@ -40,20 +41,15 @@ const MockSpellingApi = {
}
res.sendStatus(200)
})
app
.listen(3005, error => {
if (error) {
throw error
}
})
.on('error', error => {
console.error('error starting MockSpellingApi:', error.message)
process.exit(1)
})
}
}
MockSpellingApi.run()
module.exports = MockSpellingApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockSpellingApi
* @static
* @returns {MockSpellingApi}
*/

View file

@ -1,82 +1,60 @@
/* eslint-disable
max-len,
no-return-assign,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockV1Api
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
const AbstractMockApi = require('./AbstractMockApi')
const sinon = require('sinon')
app.use(bodyParser.json())
const blocklistedDomains = []
module.exports = MockV1Api = {
class MockV1Api extends AbstractMockApi {
reset() {
this.affiliations = []
this.exportId = null
this.v1Id = 1000
this.users = {}
this.allInstitutionDomains = new Set()
this.blocklistedDomains = []
this.brand_variations = {}
this.brands = {}
this.doc_exported = {}
this.docInfo = {}
this.existingEmails = []
this.brands = {}
this.brand_variations = {}
this.validation_clients = {}
this.doc_exported = {}
this.templates = {}
this.exportId = null
this.exportParams = null
this.institutionDomains = {}
this.institutionId = 1000
this.institutions = {}
this.allInstitutionDomains = new Set()
this.institutionDomains = {}
},
this.syncUserFeatures = sinon.stub()
this.templates = {}
this.updateEmail = sinon.stub()
this.users = {}
this.v1Id = 1000
this.validation_clients = {}
}
nextInstitutionId() {
return this.institutionId++
},
}
nextV1Id() {
return this.v1Id++
},
}
setUser(id, user) {
return (this.users[id] = user)
},
this.users[id] = user
}
getDocInfo(token) {
return this.docInfo[token] || null
},
}
setDocInfo(token, info) {
this.docInfo[token] = info
},
exportParams: null,
}
setExportId(id) {
return (this.exportId = id)
},
this.exportId = id
}
getLastExportParams() {
return this.exportParams
},
}
clearExportParams() {
return (this.exportParams = null)
},
syncUserFeatures: sinon.stub(),
updateEmail: sinon.stub(),
this.exportParams = null
}
createInstitution(options = {}) {
const id = options.university_id || this.nextInstitutionId()
@ -86,18 +64,18 @@ module.exports = MockV1Api = {
this.addInstitutionDomain(id, options.hostname)
}
return id
},
}
addInstitutionDomain(id, domain) {
if (this.allInstitutionDomains.has(domain)) return
if (!this.institutionDomains[id]) this.institutionDomains[id] = new Set()
this.institutionDomains[id].add(domain)
this.allInstitutionDomains.add(domain)
},
}
updateInstitution(id, options) {
Object.assign(this.institutions[id], options)
},
}
addAffiliation(userId, email) {
let institution
@ -105,7 +83,9 @@ module.exports = MockV1Api = {
const domain = email.split('@').pop()
if (blocklistedDomains.indexOf(domain.replace('.com', '')) !== -1) return
if (this.blocklistedDomains.indexOf(domain.replace('.com', '')) !== -1) {
return
}
if (this.allInstitutionDomains.has(domain)) {
for (const [id, domainSet] of Object.entries(this.institutionDomains)) {
@ -119,135 +99,132 @@ module.exports = MockV1Api = {
if (!this.affiliations[userId]) this.affiliations[userId] = []
this.affiliations[userId].push({ email, institution })
}
},
}
setAffiliations(userId, affiliations) {
this.affiliations[userId] = affiliations
},
}
setDocExported(token, info) {
return (this.doc_exported[token] = info)
},
this.doc_exported[token] = info
}
setTemplates(templates) {
this.templates = templates
},
}
run() {
app.get(
applyRoutes() {
this.app.get(
'/api/v1/sharelatex/users/:v1_user_id/plan_code',
(req, res, next) => {
(req, res) => {
const user = this.users[req.params.v1_user_id]
if (user) {
return res.json(user)
res.json(user)
} else {
return res.sendStatus(404)
res.sendStatus(404)
}
}
)
app.get(
this.app.get(
'/api/v1/sharelatex/users/:v1_user_id/subscriptions',
(req, res, next) => {
(req, res) => {
const user = this.users[req.params.v1_user_id]
if ((user != null ? user.subscription : undefined) != null) {
return res.json(user.subscription)
if (user && user.subscription) {
res.json(user.subscription)
} else {
return res.sendStatus(404)
res.sendStatus(404)
}
}
)
app.get(
this.app.get(
'/api/v1/sharelatex/users/:v1_user_id/subscription_status',
(req, res, next) => {
(req, res) => {
const user = this.users[req.params.v1_user_id]
if ((user != null ? user.subscription_status : undefined) != null) {
return res.json(user.subscription_status)
if (user && user.subscription_status) {
res.json(user.subscription_status)
} else {
return res.sendStatus(404)
res.sendStatus(404)
}
}
)
app.delete(
this.app.delete(
'/api/v1/sharelatex/users/:v1_user_id/subscription',
(req, res, next) => {
(req, res) => {
const user = this.users[req.params.v1_user_id]
if (user != null) {
if (user) {
user.canceled = true
return res.sendStatus(200)
res.sendStatus(200)
} else {
return res.sendStatus(404)
res.sendStatus(404)
}
}
)
app.post('/api/v1/sharelatex/users/:v1_user_id/sync', (req, res, next) => {
this.app.post('/api/v1/sharelatex/users/:v1_user_id/sync', (req, res) => {
this.syncUserFeatures(req.params.v1_user_id)
return res.sendStatus(200)
res.sendStatus(200)
})
app.post('/api/v1/sharelatex/exports', (req, res, next) => {
this.app.post('/api/v1/sharelatex/exports', (req, res) => {
this.exportParams = Object.assign({}, req.body)
return res.json({ exportId: this.exportId })
res.json({ exportId: this.exportId })
})
app.get('/api/v2/users/:userId/affiliations', (req, res, next) => {
return res.json(this.affiliations[req.params.userId] || [])
this.app.get('/api/v2/users/:userId/affiliations', (req, res) => {
res.json(this.affiliations[req.params.userId] || [])
})
app.post('/api/v2/users/:userId/affiliations', (req, res, next) => {
this.app.post('/api/v2/users/:userId/affiliations', (req, res) => {
this.addAffiliation(req.params.userId, req.body.email)
return res.sendStatus(201)
res.sendStatus(201)
})
app.delete('/api/v2/users/:userId/affiliations', (req, res, next) => {
return res.sendStatus(201)
this.app.delete('/api/v2/users/:userId/affiliations', (req, res) => {
res.sendStatus(201)
})
app.delete(
'/api/v2/users/:userId/affiliations/:email',
(req, res, next) => {
return res.sendStatus(204)
}
)
this.app.delete('/api/v2/users/:userId/affiliations/:email', (req, res) => {
res.sendStatus(204)
})
app.get('/api/v2/brands/:slug', (req, res, next) => {
this.app.get('/api/v2/brands/:slug', (req, res) => {
let brand
if ((brand = this.brands[req.params.slug])) {
return res.json(brand)
res.json(brand)
} else {
return res.sendStatus(404)
res.sendStatus(404)
}
})
app.get('/universities/list', (req, res, next) => res.json([]))
this.app.get('/universities/list', (req, res) => res.json([]))
app.get('/universities/list/:id', (req, res, next) =>
this.app.get('/universities/list/:id', (req, res) =>
res.json({
id: parseInt(req.params.id),
name: `Institution ${req.params.id}`
})
)
app.get('/university/domains', (req, res, next) => res.json([]))
this.app.get('/university/domains', (req, res) => res.json([]))
app.put('/api/v1/sharelatex/users/:id/email', (req, res, next) => {
const { email } = req.body != null ? req.body.user : undefined
if (Array.from(this.existingEmails).includes(email)) {
return res.sendStatus(409)
this.app.put('/api/v1/sharelatex/users/:id/email', (req, res) => {
const { email } = req.body && req.body.user
if (this.existingEmails.includes(email)) {
res.sendStatus(409)
} else {
this.updateEmail(parseInt(req.params.id), email)
return res.sendStatus(200)
res.sendStatus(200)
}
})
app.post('/api/v1/sharelatex/login', (req, res, next) => {
this.app.post('/api/v1/sharelatex/login', (req, res) => {
for (let id in this.users) {
const user = this.users[id]
if (
user != null &&
user &&
user.email === req.body.email &&
user.password === req.body.password
) {
@ -258,85 +235,74 @@ module.exports = MockV1Api = {
})
}
}
return res.status(403).json({
res.status(403).json({
email: req.body.email,
valid: false
})
})
app.get('/api/v2/partners/:partner/conversions/:id', (req, res, next) => {
this.app.get('/api/v2/partners/:partner/conversions/:id', (req, res) => {
const partner = this.validation_clients[req.params.partner]
const conversion = __guard__(
partner != null ? partner.conversions : undefined,
x => x[req.params.id]
)
if (conversion != null) {
return res.status(200).json({
const conversion =
partner && partner.conversions && partner.conversions[req.params.id]
if (conversion) {
res.status(200).json({
input_file_uri: conversion,
brand_variation_id: partner.brand_variation_id
})
} else {
return res.status(404).json({})
res.status(404).json({})
}
})
app.get('/api/v2/brand_variations/:id', (req, res, next) => {
this.app.get('/api/v2/brand_variations/:id', (req, res) => {
const variation = this.brand_variations[req.params.id]
if (variation != null) {
return res.status(200).json(variation)
if (variation) {
res.status(200).json(variation)
} else {
return res.status(404).json({})
res.status(404).json({})
}
})
app.get('/api/v1/sharelatex/docs/:token/is_published', (req, res, next) => {
this.app.get('/api/v1/sharelatex/docs/:token/is_published', (req, res) => {
return res.json({ allow: true })
})
app.get(
this.app.get(
'/api/v1/sharelatex/users/:user_id/docs/:token/info',
(req, res, next) => {
(req, res) => {
const info = this.getDocInfo(req.params.token) || {
exists: false,
exported: false
}
return res.json(info)
res.json(info)
}
)
app.get(
this.app.get(
'/api/v1/sharelatex/docs/read_token/:token/exists',
(req, res, next) => {
return res.json({ exists: false })
(req, res) => {
res.json({ exists: false })
}
)
app.get('/api/v2/templates/:templateId', (req, res, next) => {
this.app.get('/api/v2/templates/:templateId', (req, res) => {
const template = this.templates[req.params.templateId]
if (!template) {
res.sendStatus(404)
return res.sendStatus(404)
}
return res.json(template)
res.json(template)
})
return app
.listen(5000, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockV1Api:', error.message)
return process.exit(1)
})
}
}
MockV1Api.reset()
MockV1Api.run()
module.exports = MockV1Api
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockV1Api
* @static
* @returns {MockV1Api}
*/

View file

@ -1,45 +1,27 @@
/* eslint-disable
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let MockV1HistoryApi
const AbstractMockApi = require('./AbstractMockApi')
const { EventEmitter } = require('events')
const _ = require('lodash')
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
module.exports = MockV1HistoryApi = {
fakeZipCall: 0,
requestedZipPacks: 0,
sentChunks: 0,
resetCounter() {
MockV1HistoryApi.fakeZipCall = 0
MockV1HistoryApi.sentChunks = 0
MockV1HistoryApi.requestedZipPacks = 0
},
events: new EventEmitter(),
run() {
app.get(
class MockV1HistoryApi extends AbstractMockApi {
reset() {
this.fakeZipCall = 0
this.requestedZipPacks = 0
this.sentChunks = 0
this.events = new EventEmitter()
}
applyRoutes() {
this.app.get(
'/api/projects/:project_id/version/:version/zip',
(req, res, next) => {
res.header('content-disposition', 'attachment; name=project.zip')
res.header('content-type', 'application/octet-stream')
return res.send(
res.send(
`Mock zip for ${req.params.project_id} at version ${req.params.version}`
)
}
)
app.get(
this.app.get(
'/fake-zip-download/:project_id/version/:version',
(req, res, next) => {
if (!(this.fakeZipCall++ > 0)) {
@ -52,10 +34,10 @@ module.exports = MockV1HistoryApi = {
`Mock zip for ${req.params.project_id} at version ${req.params.version}`
)
}
function writeChunk() {
res.write('chunk' + MockV1HistoryApi.sentChunks++)
const writeChunk = () => {
res.write('chunk' + this.sentChunks++)
}
function writeEvery(interval) {
const writeEvery = interval => {
if (req.aborted) return
// setInterval delays the first run
@ -76,32 +58,29 @@ module.exports = MockV1HistoryApi = {
}
)
app.post(
this.app.post(
'/api/projects/:project_id/version/:version/zip',
(req, res, next) => {
MockV1HistoryApi.requestedZipPacks++
MockV1HistoryApi.events.emit('v1-history-pack-zip')
return res.json({
this.requestedZipPacks++
this.events.emit('v1-history-pack-zip')
res.json({
zipUrl: `http://localhost:3100/fake-zip-download/${req.params.project_id}/version/${req.params.version}`
})
}
)
app.delete('/api/projects/:project_id', (req, res, next) => {
this.app.delete('/api/projects/:project_id', (req, res, next) => {
res.sendStatus(204)
})
return app
.listen(3100, error => {
if (error != null) {
throw error
}
})
.on('error', error => {
console.error('error starting MockV1HistoryApi:', error.message)
return process.exit(1)
})
}
}
MockV1HistoryApi.run()
module.exports = MockV1HistoryApi
// type hint for the inherited `instance` method
/**
* @function instance
* @memberOf MockV1HistoryApi
* @static
* @returns {MockV1HistoryApi}
*/