Skip to content

Commit 91dd798

Browse files
committed
add integration test
1 parent 0e0d721 commit 91dd798

File tree

9 files changed

+18703
-6225
lines changed

9 files changed

+18703
-6225
lines changed

.prettierrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"semi": true,
3+
"trailingComma": "es5",
4+
"singleQuote": true,
5+
"arrowParens": "avoid",
6+
"printWidth": 100
7+
}

package-lock.json

Lines changed: 18425 additions & 6170 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
"pretest": "npm run lint",
88
"test": "NODE_ENV=test NODE_CONFIG_DIR=./spec/config istanbul cover -x **/spec/** jasmine --captureExceptions",
99
"lint": "eslint --cache ./",
10+
"mongo:run": "mongodb-runner start -t replset --version 6.0 -- --port 27017",
11+
"mongo:stop": "mongodb-runner stop --all",
12+
"test:integration": "npm run mongo:run && npm run test && npm run mongo:stop",
1013
"lint:fix": "eslint --fix --cache ./"
1114
},
1215
"repository": {
@@ -41,8 +44,11 @@
4144
"eslint-plugin-import": "2.22.1",
4245
"istanbul": "0.4.5",
4346
"jasmine": "3.5.0",
44-
"parse": "3.3.1",
47+
"parse": "5.3.0",
48+
"parse-server": "^7.3.0",
4549
"parse-server-conformance-tests": "1.0.0",
50+
"prettier": "3.3.3",
51+
"mongodb-runner": "5.6.4",
4652
"semantic-release": "17.4.6"
4753
}
4854
}

spec/integration.spec.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
const Parse = require('parse/node');
2+
const { TestUtils } = require('parse-server');
3+
const { PARSE_APP_ID, PARSE_MASTER_KEY, reconfigureServer, serverURL } = require('./mocks/server');
4+
const { httpRequest } = require('./support/request');
5+
6+
const fileData = 'hello world';
7+
8+
describe('S3Adapter integration tests', () => {
9+
beforeEach(async () => {
10+
process.env.TESTING = true;
11+
12+
await reconfigureServer();
13+
14+
Parse.initialize(PARSE_APP_ID);
15+
Parse.serverURL = serverURL;
16+
Parse.CoreManager.set('SERVER_URL', serverURL);
17+
Parse.CoreManager.set('MASTER_KEY', PARSE_MASTER_KEY);
18+
}, 60 * 1000);
19+
20+
afterAll(async () => {
21+
Parse.Storage._clear();
22+
await TestUtils.destroyAllDataPermanently(true);
23+
});
24+
25+
it('should create a file in Parse Server', async () => {
26+
const fileName = 'test-1.txt';
27+
28+
const base64 = Buffer.from(fileData).toString('base64');
29+
const file = new Parse.File(fileName, { base64 });
30+
31+
await file.save();
32+
33+
expect(file).toBeDefined();
34+
expect(file.url()).toContain(fileName);
35+
});
36+
37+
it(
38+
'should read the contents of the file',
39+
async () => {
40+
const fileName = 'test-2.txt';
41+
const base64 = Buffer.from(fileData).toString('base64');
42+
const file = new Parse.File(fileName, { base64 });
43+
await file.save();
44+
const fileLink = file.url();
45+
46+
const response = await httpRequest(fileLink);
47+
const text = response.toString();
48+
49+
expect(text).toBe(fileData); // Check if the contents match the original data
50+
},
51+
60 * 1000
52+
);
53+
54+
it(
55+
'should delete the file',
56+
async () => {
57+
const fileName = 'test-3.txt';
58+
59+
const base64 = Buffer.from(fileData).toString('base64');
60+
const file = new Parse.File(fileName, { base64 });
61+
await file.save();
62+
63+
const fileLink = file.url();
64+
await file.destroy();
65+
66+
return expectAsync(httpRequest(fileLink)).toBeRejectedWithError(
67+
'Request failed with status code 404'
68+
);
69+
},
70+
60 * 1000
71+
);
72+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = (options = {}) => {
2+
const adapter = {
3+
sendVerificationEmail: () => Promise.resolve(),
4+
sendPasswordResetEmail: () => Promise.resolve(),
5+
sendMail: () => Promise.resolve(),
6+
};
7+
if (options.sendMail) {
8+
adapter.sendMail = options.sendMail;
9+
}
10+
if (options.sendPasswordResetEmail) {
11+
adapter.sendPasswordResetEmail = options.sendPasswordResetEmail;
12+
}
13+
if (options.sendVerificationEmail) {
14+
adapter.sendVerificationEmail = options.sendVerificationEmail;
15+
}
16+
17+
return adapter;
18+
};

spec/mocks/s3adapter-v2.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const S3Adapter = require('../../index.js');
2+
3+
function makeS3Adapter(options) {
4+
let s3;
5+
6+
if (
7+
process.env.TEST_S3_ACCESS_KEY &&
8+
process.env.TEST_S3_SECRET_KEY &&
9+
process.env.TEST_S3_BUCKET
10+
) {
11+
// Should be initialized from the env
12+
s3 = new S3Adapter(
13+
Object.assign(
14+
{
15+
accessKey: process.env.TEST_S3_ACCESS_KEY,
16+
secretKey: process.env.TEST_S3_SECRET_KEY,
17+
bucket: process.env.TEST_S3_BUCKET,
18+
},
19+
options
20+
)
21+
);
22+
} else {
23+
const bucket = 'FAKE_BUCKET';
24+
25+
s3 = new S3Adapter('FAKE_ACCESS_KEY', 'FAKE_SECRET_KEY', bucket, options);
26+
27+
const objects = {};
28+
29+
s3._s3Client = {
30+
createBucket: callback => setTimeout(callback, 100),
31+
upload: (params, callback) =>
32+
setTimeout(() => {
33+
const { Key, Body } = params;
34+
35+
objects[Key] = Body;
36+
37+
callback(null, {
38+
Location: `https://${bucket}.s3.amazonaws.com/${Key}`,
39+
});
40+
}, 100),
41+
deleteObject: (params, callback) =>
42+
setTimeout(() => {
43+
const { Key } = params;
44+
45+
delete objects[Key];
46+
47+
callback(null, {});
48+
}, 100),
49+
getObject: (params, callback) =>
50+
setTimeout(() => {
51+
const { Key } = params;
52+
53+
if (objects[Key]) {
54+
callback(null, {
55+
Body: Buffer.from(objects[Key], 'utf8'),
56+
});
57+
} else {
58+
callback(new Error('Not found'));
59+
}
60+
}, 100),
61+
};
62+
}
63+
return s3;
64+
}
65+
66+
module.exports = { makeS3Adapter };

spec/mocks/server.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
const { ParseServer } = require('parse-server');
2+
const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
3+
const { makeS3Adapter } = require('./s3adapter-v2');
4+
5+
const port = 1327;
6+
const mountPath = '/api/parse';
7+
const serverURL = 'http://127.0.0.1:1327/api/parse';
8+
9+
const PARSE_APP_ID = 'app-id';
10+
const PARSE_MASTER_KEY = 'master-key';
11+
12+
const S3Adapter = makeS3Adapter();
13+
14+
const defaultConfiguration = {
15+
databaseURI: 'mongodb://127.0.0.1:27017/s3-adapter',
16+
appId: PARSE_APP_ID,
17+
masterKey: PARSE_MASTER_KEY,
18+
serverURL,
19+
liveQuery: {
20+
classNames: [],
21+
},
22+
startLiveQueryServer: true,
23+
verbose: false,
24+
silent: true,
25+
fileUpload: {
26+
enableForPublic: true,
27+
enableForAnonymousUser: true,
28+
enableForAuthenticatedUser: true,
29+
},
30+
revokeSessionOnPasswordReset: false,
31+
allowCustomObjectId: false,
32+
allowClientClassCreation: true,
33+
encodeParseObjectInCloudFunction: true,
34+
masterKeyIps: ['0.0.0.0/0', '0.0.0.0', '::/0', '::'],
35+
emailAdapter: MockEmailAdapterWithOptions(),
36+
port,
37+
mountPath,
38+
filesAdapter: S3Adapter,
39+
};
40+
41+
let parseServer;
42+
43+
const reconfigureServer = async () => {
44+
if (parseServer) {
45+
await parseServer.handleShutdown();
46+
await new Promise(resolve => parseServer.server.close(resolve));
47+
parseServer = undefined;
48+
return reconfigureServer();
49+
}
50+
51+
parseServer = await ParseServer.startApp(defaultConfiguration);
52+
if (parseServer.config.state === 'initialized') {
53+
console.error('Failed to initialize Parse Server');
54+
return reconfigureServer();
55+
}
56+
57+
return parseServer;
58+
};
59+
60+
module.exports = {
61+
reconfigureServer,
62+
S3Adapter,
63+
port,
64+
mountPath,
65+
serverURL,
66+
PARSE_APP_ID,
67+
PARSE_MASTER_KEY,
68+
};

spec/support/request.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const http = require('http');
2+
const https = require('https');
3+
4+
/**
5+
* Makes an HTTP or HTTPS request.
6+
* @param {string} url - The URL to request.
7+
* @returns {Promise<string>} - A promise that resolves with the response data or rejects with an error.
8+
*/
9+
function httpRequest(url) {
10+
return new Promise((resolve, reject) => {
11+
// Determine the appropriate module to use based on the URL protocol
12+
const client = url.startsWith('https') ? https : http;
13+
14+
// Make the request
15+
client
16+
.get(url, response => {
17+
let data = '';
18+
19+
// Collect the data chunks
20+
response.on('data', chunk => {
21+
data += chunk;
22+
});
23+
24+
// When the response ends, resolve or reject the promise
25+
response.on('end', () => {
26+
if (response.statusCode >= 200 && response.statusCode < 300) {
27+
resolve(data); // Resolve with the collected data
28+
} else {
29+
reject(new Error(`Request failed with status code ${response.statusCode}`));
30+
}
31+
});
32+
})
33+
.on('error', error => {
34+
reject(new Error(`Error making request: ${error.message}`)); // Reject on error
35+
});
36+
});
37+
}
38+
39+
module.exports = { httpRequest };

spec/test.spec.js

Lines changed: 1 addition & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,9 @@ const filesAdapterTests = require('parse-server-conformance-tests').files;
44
const Parse = require('parse').Parse;
55
const S3Adapter = require('../index.js');
66
const optionsFromArguments = require('../lib/optionsFromArguments');
7+
const {makeS3Adapter} = require("./mocks/s3adapter-v2.js");
78

89
describe('S3Adapter tests', () => {
9-
function makeS3Adapter(options) {
10-
let s3;
11-
12-
if (
13-
process.env.TEST_S3_ACCESS_KEY
14-
&& process.env.TEST_S3_SECRET_KEY
15-
&& process.env.TEST_S3_BUCKET) {
16-
// Should be initialized from the env
17-
s3 = new S3Adapter(Object.assign({
18-
accessKey: process.env.TEST_S3_ACCESS_KEY,
19-
secretKey: process.env.TEST_S3_SECRET_KEY,
20-
bucket: process.env.TEST_S3_BUCKET,
21-
}, options));
22-
} else {
23-
const bucket = 'FAKE_BUCKET';
24-
25-
s3 = new S3Adapter('FAKE_ACCESS_KEY', 'FAKE_SECRET_KEY', bucket, options);
26-
27-
const objects = {};
28-
29-
s3._s3Client = {
30-
createBucket: (callback) => setTimeout(callback, 100),
31-
upload: (params, callback) => setTimeout(() => {
32-
const { Key, Body } = params;
33-
34-
objects[Key] = Body;
35-
36-
callback(null, {
37-
Location: `https://${bucket}.s3.amazonaws.com/${Key}`,
38-
});
39-
}, 100),
40-
deleteObject: (params, callback) => setTimeout(() => {
41-
const { Key } = params;
42-
43-
delete objects[Key];
44-
45-
callback(null, {});
46-
}, 100),
47-
getObject: (params, callback) => setTimeout(() => {
48-
const { Key } = params;
49-
50-
if (objects[Key]) {
51-
callback(null, {
52-
Body: Buffer.from(objects[Key], 'utf8'),
53-
});
54-
} else {
55-
callback(new Error('Not found'));
56-
}
57-
}, 100),
58-
};
59-
}
60-
return s3;
61-
}
62-
6310
beforeEach(() => {
6411
delete process.env.S3_BUCKET;
6512
delete process.env.S3_REGION;

0 commit comments

Comments
 (0)