Database version in features (#5627)
* adding database.version in the serverInfo (only MongoDB, it gives undefined when using Postgres) * . correction of old 'features' tests . adding engine and database in the StorageAdapter interface and implementations * . version retrieval done in performInitialization . PostgreSQL version * performInitialization now returns a Promise
This commit is contained in:
committed by
Diamond Lewis
parent
266d6328a3
commit
7fc0d45b89
@@ -3,20 +3,41 @@
|
|||||||
const request = require('../lib/request');
|
const request = require('../lib/request');
|
||||||
|
|
||||||
describe('features', () => {
|
describe('features', () => {
|
||||||
it('requires the master key to get features', done => {
|
it('should return the serverInfo', async () => {
|
||||||
request({
|
const response = await request({
|
||||||
url: 'http://localhost:8378/1/serverInfo',
|
url: 'http://localhost:8378/1/serverInfo',
|
||||||
json: true,
|
json: true,
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': 'test',
|
'X-Parse-Application-Id': 'test',
|
||||||
'X-Parse-REST-API-Key': 'rest',
|
'X-Parse-REST-API-Key': 'rest',
|
||||||
|
'X-Parse-Master-Key': 'test',
|
||||||
},
|
},
|
||||||
}).then(fail, response => {
|
|
||||||
expect(response.status).toEqual(403);
|
|
||||||
expect(response.data.error).toEqual(
|
|
||||||
'unauthorized: master key is required'
|
|
||||||
);
|
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
|
const data = response.data;
|
||||||
|
expect(data).toBeDefined();
|
||||||
|
expect(data.features).toBeDefined();
|
||||||
|
expect(data.parseServerVersion).toBeDefined();
|
||||||
|
expect(data.database).toBeDefined();
|
||||||
|
expect(['MongoDB', 'PostgreSQL']).toContain(data.database.engine);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('requires the master key to get features', async done => {
|
||||||
|
try {
|
||||||
|
await request({
|
||||||
|
url: 'http://localhost:8378/1/serverInfo',
|
||||||
|
json: true,
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Application-Id': 'test',
|
||||||
|
'X-Parse-REST-API-Key': 'rest',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
done.fail(
|
||||||
|
'The serverInfo request should be rejected without the master key'
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.status).toEqual(403);
|
||||||
|
expect(error.data.error).toEqual('unauthorized: master key is required');
|
||||||
|
done();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -126,6 +126,8 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
client: MongoClient;
|
client: MongoClient;
|
||||||
_maxTimeMS: ?number;
|
_maxTimeMS: ?number;
|
||||||
canSortOnJoinTables: boolean;
|
canSortOnJoinTables: boolean;
|
||||||
|
databaseVersion: string;
|
||||||
|
engine: string;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
uri = defaults.DefaultMongoURI,
|
uri = defaults.DefaultMongoURI,
|
||||||
@@ -136,6 +138,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
this._collectionPrefix = collectionPrefix;
|
this._collectionPrefix = collectionPrefix;
|
||||||
this._mongoOptions = mongoOptions;
|
this._mongoOptions = mongoOptions;
|
||||||
this._mongoOptions.useNewUrlParser = true;
|
this._mongoOptions.useNewUrlParser = true;
|
||||||
|
this.engine = 'MongoDB';
|
||||||
|
|
||||||
// MaxTimeMS is not a global MongoDB client option, it is applied per operation.
|
// MaxTimeMS is not a global MongoDB client option, it is applied per operation.
|
||||||
this._maxTimeMS = mongoOptions.maxTimeMS;
|
this._maxTimeMS = mongoOptions.maxTimeMS;
|
||||||
@@ -959,7 +962,15 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
performInitialization(): Promise<void> {
|
performInitialization(): Promise<void> {
|
||||||
return Promise.resolve();
|
// databaseVersion
|
||||||
|
return this.connect()
|
||||||
|
.then(() => {
|
||||||
|
const adminDb = this.database.admin();
|
||||||
|
return adminDb.serverStatus();
|
||||||
|
})
|
||||||
|
.then(status => {
|
||||||
|
this.databaseVersion = status.version;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createIndex(className: string, index: any) {
|
createIndex(className: string, index: any) {
|
||||||
|
|||||||
@@ -778,6 +778,8 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
|
|||||||
|
|
||||||
export class PostgresStorageAdapter implements StorageAdapter {
|
export class PostgresStorageAdapter implements StorageAdapter {
|
||||||
canSortOnJoinTables: boolean;
|
canSortOnJoinTables: boolean;
|
||||||
|
databaseVersion: string;
|
||||||
|
engine: string;
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
_collectionPrefix: string;
|
_collectionPrefix: string;
|
||||||
@@ -790,6 +792,7 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
this._client = client;
|
this._client = client;
|
||||||
this._pgp = pgp;
|
this._pgp = pgp;
|
||||||
this.canSortOnJoinTables = false;
|
this.canSortOnJoinTables = false;
|
||||||
|
this.engine = 'PostgreSQL';
|
||||||
}
|
}
|
||||||
|
|
||||||
handleShutdown() {
|
handleShutdown() {
|
||||||
@@ -2276,6 +2279,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
|
|||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
debug(`initializationDone in ${data.duration}`);
|
debug(`initializationDone in ${data.duration}`);
|
||||||
|
// databaseVersion
|
||||||
|
return this._client.query('SHOW server_version');
|
||||||
|
})
|
||||||
|
.then(versionData => {
|
||||||
|
// versionData is like [ { server_version: '11.3' } ]
|
||||||
|
this.databaseVersion = versionData[0].server_version;
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export type FullQueryOptions = QueryOptions & UpdateQueryOptions;
|
|||||||
|
|
||||||
export interface StorageAdapter {
|
export interface StorageAdapter {
|
||||||
canSortOnJoinTables: boolean;
|
canSortOnJoinTables: boolean;
|
||||||
|
databaseVersion: string;
|
||||||
|
engine: string;
|
||||||
|
|
||||||
classExists(className: string): Promise<boolean>;
|
classExists(className: string): Promise<boolean>;
|
||||||
setClassLevelPermissions(className: string, clps: any): Promise<void>;
|
setClassLevelPermissions(className: string, clps: any): Promise<void>;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export class FeaturesRouter extends PromiseRouter {
|
|||||||
'/serverInfo',
|
'/serverInfo',
|
||||||
middleware.promiseEnforceMasterKeyAccess,
|
middleware.promiseEnforceMasterKeyAccess,
|
||||||
req => {
|
req => {
|
||||||
|
const { config } = req;
|
||||||
const features = {
|
const features = {
|
||||||
globalConfig: {
|
globalConfig: {
|
||||||
create: true,
|
create: true,
|
||||||
@@ -33,9 +34,9 @@ export class FeaturesRouter extends PromiseRouter {
|
|||||||
from: true,
|
from: true,
|
||||||
},
|
},
|
||||||
push: {
|
push: {
|
||||||
immediatePush: req.config.hasPushSupport,
|
immediatePush: config.hasPushSupport,
|
||||||
scheduledPush: req.config.hasPushScheduledSupport,
|
scheduledPush: config.hasPushScheduledSupport,
|
||||||
storedPushData: req.config.hasPushSupport,
|
storedPushData: config.hasPushSupport,
|
||||||
pushAudiences: true,
|
pushAudiences: true,
|
||||||
localization: true,
|
localization: true,
|
||||||
},
|
},
|
||||||
@@ -51,10 +52,15 @@ export class FeaturesRouter extends PromiseRouter {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const dbAdapter = config.database.adapter;
|
||||||
return {
|
return {
|
||||||
response: {
|
response: {
|
||||||
features: features,
|
features: features,
|
||||||
parseServerVersion: version,
|
parseServerVersion: version,
|
||||||
|
database: {
|
||||||
|
engine: dbAdapter.engine,
|
||||||
|
version: dbAdapter.databaseVersion,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user