Migrate admin-regenerate-manifest.js to mocha.js and test v3 UI code
[WebKit-https.git] / Websites / perf.webkit.org / server-tests / resources / test-server.js
1 'use strict';
2
3 let assert = require('assert');
4 let childProcess = require('child_process');
5 let fs = require('fs');
6 let path = require('path');
7
8 let Config = require('../../tools/js/config.js');
9 let Database = require('../../tools/js/database.js');
10 let RemoteAPI = require('../../tools/js/remote.js').RemoteAPI;
11
12 let TestServer = (new class TestServer {
13     constructor()
14     {
15         this._pidFile = null;
16         this._testConfigPath = Config.path('testServer.config');
17         this._dataDirectory = Config.path('dataDirectory');
18         this._backupDataPath = null;
19         this._pidWaitStart = null;
20         this._shouldLog = false;
21         this._pgsqlDirectory = null;
22         this._server = null;
23
24         this._databaseName = Config.value('testDatabaseName');
25         this._databaseUser = Config.value('database.username');
26         this._databaseHost = Config.value('database.host');
27         this._databasePort = Config.value('database.port');
28         this._database = null;
29     }
30
31     start()
32     {        
33         let testConfigContent = this.testConfig();
34         fs.writeFileSync(this._testConfigPath, JSON.stringify(testConfigContent, null, '    '));
35
36         this._ensureTestDatabase();
37         this._ensureDataDirectory();
38
39         return this._startApache();
40     }
41
42     stop()
43     {
44         this._restoreDataDirectory();
45
46         return this._stopApache();
47     }
48
49     remoteAPI()
50     {
51         assert(this._server);
52         RemoteAPI.configure(this._server);
53         return RemoteAPI;
54     }
55
56     database()
57     {
58         assert(this._databaseName);
59         if (!this._database)
60             this._database = new Database(this._databaseName);
61         return this._database;
62     }
63
64     testConfig()
65     {
66         return {
67             'siteTitle': 'Test Dashboard',
68             'debug': true,
69             'jsonCacheMaxAge': 600,
70             'dataDirectory': Config.value('dataDirectory'),
71             'database': {
72                 'host': Config.value('database.host'),
73                 'port': Config.value('database.port'),
74                 'username': Config.value('database.username'),
75                 'password': Config.value('database.password'),
76                 'name': Config.value('testDatabaseName'),
77             },
78             'universalSlavePassword': null,
79             'maintenanceMode': false,
80             'clusterStart': [2000, 1, 1, 0, 0],
81             'clusterSize': [0, 2, 0],
82             'defaultDashboard': [[]],
83             'dashboards': {}
84         }
85     }
86
87     _ensureDataDirectory()
88     {
89         let backupPath = path.resolve(this._dataDirectory, '../original-data');
90         if (fs.existsSync(this._dataDirectory)) {
91             assert.ok(!fs.existsSync(backupPath), `Both ${this._dataDirectory} and ${backupPath} exist. Cannot make a backup of data`);
92             fs.renameSync(this._dataDirectory, backupPath);
93             this._backupDataPath = backupPath;
94         } else if (fs.existsSync(backupPath)) // Assume this is a backup from the last failed run
95             this._backupDataPath = backupPath;
96         fs.mkdirSync(this._dataDirectory, 0o755);
97     }
98
99     _restoreDataDirectory()
100     {
101         childProcess.execFileSync('rm', ['-rf', this._dataDirectory]);
102         if (this._backupDataPath)
103             fs.rename(this._backupDataPath, this._dataDirectory);
104     }
105
106     cleanDataDirectory()
107     {
108         let fileList = fs.readdirSync(this._dataDirectory);
109         for (let filename of fileList)
110             fs.unlinkSync(path.resolve(this._dataDirectory, filename));
111     }
112
113     _ensureTestDatabase()
114     {
115         this._executePgsqlCommand('dropdb');
116         this._executePgsqlCommand('createdb');
117         this._executePgsqlCommand('psql', ['--command', `grant all privileges on database "${this._databaseName}" to "${this._databaseUser}";`]);
118         this.initDatabase();
119     }
120
121     initDatabase()
122     {
123         if (this._database)
124             this._database.disconnect();
125         this._database = null;
126
127         let initFilePath = Config.pathFromRoot('init-database.sql');
128         this._executePgsqlCommand('psql', ['--username', this._databaseUser, '--file', initFilePath],
129             {stdio: ['ignore', 'ignore', 'ignore']});
130     }
131
132     _executePgsqlCommand(command, args, options)
133     {
134         if (!this._pgsqlDirectory)
135             this._pgsqlDirectory = this._determinePgsqlDirectory();
136         childProcess.execFileSync(path.resolve(this._pgsqlDirectory, command),
137             [this._databaseName, '--host', this._databaseHost, '--port', this._databasePort].concat(args || []), options);
138     }
139
140     _determinePgsqlDirectory()
141     {
142         try {
143             let initdbLocation = childProcess.execFileSync('which', ['initdb']);
144             return path.dirname(initdbLocation);
145         } catch (error) {
146             let serverPgsqlLocation = '/Applications/Server.app/Contents/ServerRoot/usr/bin/';
147             childProcess.execFileSync(path.resolve(serverPgsqlLocation, 'initdb'), ['--version']);
148             return serverPgsqlLocation;
149         }
150     }
151
152     _startApache()
153     {
154         let pidFile = Config.path('testServer.httpdPID');
155         let httpdConfig = Config.path('testServer.httpdConfig');
156         let port = Config.value('testServer.port');
157         let errorLog = Config.path('testServer.httpdErrorLog');
158         let mutexFile = Config.path('testServer.httpdMutexDir');
159
160         if (!fs.existsSync(mutexFile))
161             fs.mkdirSync(mutexFile, 0o755);
162
163         let args = [
164             '-f', httpdConfig,
165             '-c', `SetEnv ORG_WEBKIT_PERF_CONFIG_PATH ${this._testConfigPath}`,
166             '-c', `Listen ${port}`,
167             '-c', `PidFile ${pidFile}`,
168             '-c', `ErrorLog ${errorLog}`,
169             '-c', `Mutex file:${mutexFile}`,
170             '-c', `DocumentRoot ${Config.serverRoot()}`];
171
172         if (this._shouldLog)
173             console.log(args);
174
175         childProcess.execFileSync('httpd', args);
176
177         this._server = {
178             scheme: 'http',
179             host: 'localhost',
180             port: port,
181         }
182         this._pidWaitStart = Date.now();
183         this._pidFile = pidFile;
184         return new Promise(this._waitForPid.bind(this, true));
185     }
186
187     _stopApache()
188     {
189         if (!this._pidFile)
190             return;
191
192         let pid = fs.readFileSync(this._pidFile, 'utf-8').trim();
193
194         if (this._shouldLog)
195             console.log('Stopping', pid);
196
197         childProcess.execFileSync('kill', ['-TERM', pid]);
198
199         return new Promise(this._waitForPid.bind(this, false));
200     }
201
202     _waitForPid(shouldExist, resolve, reject)
203     {
204         if (fs.existsSync(this._pidFile) != shouldExist) {
205             if (Date.now() - this._pidWaitStart > 5000)
206                 reject();
207             else
208                 setTimeout(this._waitForPid.bind(this, shouldExist, resolve, reject), 100);
209             return;
210         }
211         resolve();
212     }
213
214     inject()
215     {
216         let self = this;
217         before(function () {
218             this.timeout(5000);
219             return self.start();
220         });
221
222         beforeEach(function () {
223             this.timeout(10000);
224             self.initDatabase();
225             self.cleanDataDirectory();
226         });
227
228         after(function () {
229             this.timeout(5000);
230             return self.stop();
231         });
232     }
233 });
234
235
236 if (typeof module != 'undefined')
237     module.exports = TestServer;