From f996c9516519d10851b1c59093751589852489ab Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 2 Feb 2023 09:55:25 +0000 Subject: [PATCH] Merge pull request #11593 from overleaf/bg-create-project-with-random-history extend the create_project script to include history GitOrigin-RevId: 74084731d72337eecd933a31212000f64026df8b --- services/web/scripts/create_project.js | 108 ++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/services/web/scripts/create_project.js b/services/web/scripts/create_project.js index 52555d11e9..21c067569b 100644 --- a/services/web/scripts/create_project.js +++ b/services/web/scripts/create_project.js @@ -4,17 +4,19 @@ const fs = require('fs') const path = require('path') -const _ = require('underscore') +const _ = require('lodash') const parseArgs = require('minimist') const OError = require('@overleaf/o-error') const { waitForDb } = require('../app/src/infrastructure/mongodb') const { User } = require('../app/src/models/User') const ProjectCreationHandler = require('../app/src/Features/Project/ProjectCreationHandler') const ProjectEntityUpdateHandler = require('../app/src/Features/Project/ProjectEntityUpdateHandler') +const ProjectEntityHandler = require('../app/src/Features/Project/ProjectEntityHandler') +const EditorController = require('../app/src/Features/Editor/EditorController') const argv = parseArgs(process.argv.slice(2), { string: ['user-id', 'name'], - boolean: ['old-history'], + boolean: ['old-history', 'random-content'], unknown: function (arg) { console.error('unrecognised argument', arg) process.exit(1) @@ -26,6 +28,7 @@ console.log('argv', argv) const userId = argv['user-id'] const projectName = argv.name || `Test Project ${new Date().toISOString()}` const oldHistory = argv['old-history'] +const randomContent = argv['random-content'] console.log('userId', userId) @@ -100,6 +103,102 @@ async function _buildTemplate(templateName, userId, projectName) { return output.split('\n') } +// Create a project with some random content and file operations for testing history migrations +// Unfortunately we cannot easily change the timestamps of the history entries, so everything +// will be created at the same time. + +async function _pickRandomDoc(project) { + const result = await ProjectEntityHandler.promises.getAllDocs(project._id) + const keys = Object.keys(result) + if (keys.length === 0) { + return null + } + const filepath = _.sample(keys) + result[filepath].path = filepath + return result[filepath] +} + +let COUNTER = 0 +// format counter as a 6 digit zero padded number +function nextId() { + return ('000000' + COUNTER++).slice(-6) +} + +async function _applyRandomDocUpdate(ownerId, project) { + const action = _.sample(['create', 'edit', 'delete', 'rename']) + switch (action) { + case 'create': // create a new doc + await EditorController.promises.upsertDocWithPath( + project._id, + `subdir/new-doc-${nextId()}.tex`, + [`This is a new doc ${new Date().toISOString()}`], + 'create-project-script', + ownerId + ) + break + case 'edit': { + // edit an existing doc + const doc = await _pickRandomDoc(project) + if (!doc) { + return + } + // pick a random line and either insert or delete a character + const lines = doc.lines + const index = _.random(0, lines.length - 1) + let thisLine = lines[index] + const pos = _.random(0, thisLine.length - 1) + if (Math.random() > 0.5) { + // insert a character + thisLine = thisLine.slice(0, pos) + 'x' + thisLine.slice(pos) + } else { + // delete a character + thisLine = thisLine.slice(0, pos) + thisLine.slice(pos + 1) + } + lines[index] = thisLine + await EditorController.promises.upsertDocWithPath( + project._id, + doc.path, + lines, + 'create-project-script', + ownerId + ) + break + } + case 'delete': { + // delete an existing doc (but not the root doc) + const doc = await _pickRandomDoc(project) + if (!doc || doc.path === '/main.tex') { + return + } + + await EditorController.promises.deleteEntityWithPath( + project._id, + doc.path, + ownerId, + 'create-project-script' + ) + break + } + case 'rename': { + // rename an existing doc (but not the root doc) + const doc = await _pickRandomDoc(project) + if (!doc || doc.path === '/main.tex') { + return + } + const newName = `renamed-${nextId()}.tex` + await EditorController.promises.renameEntity( + project._id, + doc._id, + 'doc', + newName, + ownerId, + 'create-project-script' + ) + break + } + } +} + async function createProject() { await waitForDb() const user = await User.findById(userId) @@ -113,6 +212,11 @@ async function createProject() { attributes ) await _addDefaultExampleProjectFiles(userId, projectName, project) + if (randomContent) { + for (let i = 0; i < 1000; i++) { + await _applyRandomDocUpdate(userId, project) + } + } return project }