Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci: Add integration tests for Parse Server #224

Merged
merged 33 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
91dd798
add integration test
vahidalizad Oct 13, 2024
a11e409
revert parse js sdk version
vahidalizad Oct 16, 2024
09fc315
remove unused configs in integration tests setup
vahidalizad Oct 16, 2024
7add3cf
Merge branch 'master' into integration-test
vahidalizad Oct 22, 2024
90cda17
add index to coverage
vahidalizad Oct 22, 2024
7599610
Update package.json
mtrezza Oct 22, 2024
1c4682f
refactor server integration
mtrezza Oct 22, 2024
cf76ac9
remove server options
mtrezza Oct 22, 2024
782d598
fix lint
mtrezza Oct 22, 2024
763f5ef
fix lint
mtrezza Oct 22, 2024
2fb1e14
regenerate package-lock
mtrezza Oct 22, 2024
ac98bb4
upgrade aws sdk
mtrezza Oct 22, 2024
4b3228c
Merge branch 'master' into integration-test
mtrezza Oct 22, 2024
2270c56
clean up tests
mtrezza Oct 22, 2024
6726c96
remove lib from nyc
mtrezza Oct 22, 2024
6a02150
Revert "remove lib from nyc"
mtrezza Oct 22, 2024
0b7ea2a
rename tests
mtrezza Oct 22, 2024
70e55db
fix ts errors
mtrezza Oct 22, 2024
aa5d07e
refactor integr test
mtrezza Oct 22, 2024
9457f2e
remove conformance tests
mtrezza Oct 22, 2024
291d9dd
Update package-lock.json
mtrezza Oct 22, 2024
ae0930d
add parse server compat
mtrezza Oct 22, 2024
dd95fe0
fix testing env var
mtrezza Oct 22, 2024
cd454a9
Update package-lock.json
mtrezza Oct 22, 2024
31f0715
Update .gitignore
mtrezza Oct 22, 2024
2b21b55
Update README.md
mtrezza Oct 22, 2024
c3fcc29
add parse server matrix
mtrezza Oct 22, 2024
5f1cf60
Update jasmine.js
mtrezza Oct 22, 2024
a21f2f9
Update jasmine.js
mtrezza Oct 22, 2024
957b085
fix lint
mtrezza Oct 22, 2024
3ff1bf8
remove parse server 5 test
mtrezza Oct 22, 2024
d95d10e
Update ci.yml
mtrezza Oct 22, 2024
fe0e6ab
remove prettier
mtrezza Oct 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"arrowParens": "avoid",
"printWidth": 100
}
24,595 changes: 18,425 additions & 6,170 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"pretest": "npm run lint",
"test": "NODE_ENV=test NODE_CONFIG_DIR=./spec/config istanbul cover -x **/spec/** jasmine --captureExceptions",
"lint": "eslint --cache ./",
"mongo:run": "mongodb-runner start -t replset --version 6.0 -- --port 27017",
"mongo:stop": "mongodb-runner stop --all",
"test:integration": "npm run mongo:run && npm run test && npm run mongo:stop",
"lint:fix": "eslint --fix --cache ./"
},
"repository": {
Expand Down Expand Up @@ -41,8 +44,11 @@
"eslint-plugin-import": "2.22.1",
"istanbul": "0.4.5",
"jasmine": "3.5.0",
"parse": "3.3.1",
"parse": "5.3.0",
vahidalizad marked this conversation as resolved.
Show resolved Hide resolved
"parse-server": "^7.3.0",
"parse-server-conformance-tests": "1.0.0",
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
"prettier": "3.3.3",
"mongodb-runner": "5.6.4",
"semantic-release": "17.4.6"
}
}
72 changes: 72 additions & 0 deletions spec/integration.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const Parse = require('parse/node');
const { TestUtils } = require('parse-server');
const { PARSE_APP_ID, PARSE_MASTER_KEY, reconfigureServer, serverURL } = require('./mocks/server');
const { httpRequest } = require('./support/request');

const fileData = 'hello world';

describe('S3Adapter integration tests', () => {
beforeEach(async () => {
process.env.TESTING = true;

await reconfigureServer();

Parse.initialize(PARSE_APP_ID);
Parse.serverURL = serverURL;
Parse.CoreManager.set('SERVER_URL', serverURL);
Parse.CoreManager.set('MASTER_KEY', PARSE_MASTER_KEY);
}, 60 * 1000);

afterAll(async () => {
Parse.Storage._clear();
await TestUtils.destroyAllDataPermanently(true);
});

it('should create a file in Parse Server', async () => {
const fileName = 'test-1.txt';

const base64 = Buffer.from(fileData).toString('base64');
const file = new Parse.File(fileName, { base64 });

await file.save();

expect(file).toBeDefined();
expect(file.url()).toContain(fileName);
});

it(
'should read the contents of the file',
async () => {
const fileName = 'test-2.txt';
const base64 = Buffer.from(fileData).toString('base64');
const file = new Parse.File(fileName, { base64 });
await file.save();
const fileLink = file.url();

const response = await httpRequest(fileLink);
const text = response.toString();

expect(text).toBe(fileData); // Check if the contents match the original data
},
60 * 1000
);

it(
'should delete the file',
async () => {
const fileName = 'test-3.txt';

const base64 = Buffer.from(fileData).toString('base64');
const file = new Parse.File(fileName, { base64 });
await file.save();

const fileLink = file.url();
await file.destroy();

return expectAsync(httpRequest(fileLink)).toBeRejectedWithError(
'Request failed with status code 404'
);
},
60 * 1000
);
});
18 changes: 18 additions & 0 deletions spec/mocks/MockEmailAdapterWithOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = (options = {}) => {
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
const adapter = {
sendVerificationEmail: () => Promise.resolve(),
sendPasswordResetEmail: () => Promise.resolve(),
sendMail: () => Promise.resolve(),
};
if (options.sendMail) {
adapter.sendMail = options.sendMail;
}
if (options.sendPasswordResetEmail) {
adapter.sendPasswordResetEmail = options.sendPasswordResetEmail;
}
if (options.sendVerificationEmail) {
adapter.sendVerificationEmail = options.sendVerificationEmail;
}

return adapter;
};
66 changes: 66 additions & 0 deletions spec/mocks/s3adapter-v2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const S3Adapter = require('../../index.js');

function makeS3Adapter(options) {
let s3;

if (
process.env.TEST_S3_ACCESS_KEY &&
process.env.TEST_S3_SECRET_KEY &&
process.env.TEST_S3_BUCKET
) {
// Should be initialized from the env
s3 = new S3Adapter(
Object.assign(
{
accessKey: process.env.TEST_S3_ACCESS_KEY,
secretKey: process.env.TEST_S3_SECRET_KEY,
bucket: process.env.TEST_S3_BUCKET,
},
options
)
);
} else {
const bucket = 'FAKE_BUCKET';

s3 = new S3Adapter('FAKE_ACCESS_KEY', 'FAKE_SECRET_KEY', bucket, options);

const objects = {};

s3._s3Client = {
createBucket: callback => setTimeout(callback, 100),
upload: (params, callback) =>
setTimeout(() => {
const { Key, Body } = params;

objects[Key] = Body;

callback(null, {
Location: `https://${bucket}.s3.amazonaws.com/${Key}`,
});
}, 100),
deleteObject: (params, callback) =>
setTimeout(() => {
const { Key } = params;

delete objects[Key];

callback(null, {});
}, 100),
getObject: (params, callback) =>
setTimeout(() => {
const { Key } = params;

if (objects[Key]) {
callback(null, {
Body: Buffer.from(objects[Key], 'utf8'),
});
} else {
callback(new Error('Not found'));
}
}, 100),
};
}
return s3;
}

module.exports = { makeS3Adapter };
68 changes: 68 additions & 0 deletions spec/mocks/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const { ParseServer } = require('parse-server');
const MockEmailAdapterWithOptions = require('./MockEmailAdapterWithOptions');
const { makeS3Adapter } = require('./s3adapter-v2');

const port = 1327;
const mountPath = '/api/parse';
const serverURL = 'http://127.0.0.1:1327/api/parse';

const PARSE_APP_ID = 'app-id';
const PARSE_MASTER_KEY = 'master-key';

const S3Adapter = makeS3Adapter();

const defaultConfiguration = {
databaseURI: 'mongodb://127.0.0.1:27017/s3-adapter',
appId: PARSE_APP_ID,
masterKey: PARSE_MASTER_KEY,
serverURL,
liveQuery: {
classNames: [],
},
startLiveQueryServer: true,
verbose: false,
silent: true,
fileUpload: {
enableForPublic: true,
enableForAnonymousUser: true,
enableForAuthenticatedUser: true,
},
revokeSessionOnPasswordReset: false,
allowCustomObjectId: false,
allowClientClassCreation: true,
encodeParseObjectInCloudFunction: true,
vahidalizad marked this conversation as resolved.
Show resolved Hide resolved
masterKeyIps: ['0.0.0.0/0', '0.0.0.0', '::/0', '::'],
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
emailAdapter: MockEmailAdapterWithOptions(),
port,
mountPath,
filesAdapter: S3Adapter,
};

let parseServer;

const reconfigureServer = async () => {
if (parseServer) {
await parseServer.handleShutdown();
await new Promise(resolve => parseServer.server.close(resolve));
parseServer = undefined;
return reconfigureServer();
}

parseServer = await ParseServer.startApp(defaultConfiguration);
if (parseServer.config.state === 'initialized') {
console.error('Failed to initialize Parse Server');
return reconfigureServer();
}

return parseServer;
};

module.exports = {
reconfigureServer,
S3Adapter,
port,
mountPath,
serverURL,
PARSE_APP_ID,
PARSE_MASTER_KEY,
};
39 changes: 39 additions & 0 deletions spec/support/request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
const http = require('http');
const https = require('https');

/**
* Makes an HTTP or HTTPS request.
* @param {string} url - The URL to request.
* @returns {Promise<string>} - A promise that resolves with the response data or rejects with an error.
*/
function httpRequest(url) {
return new Promise((resolve, reject) => {
// Determine the appropriate module to use based on the URL protocol
const client = url.startsWith('https') ? https : http;

// Make the request
client
.get(url, response => {
let data = '';

// Collect the data chunks
response.on('data', chunk => {
data += chunk;
});

// When the response ends, resolve or reject the promise
response.on('end', () => {
if (response.statusCode >= 200 && response.statusCode < 300) {
resolve(data); // Resolve with the collected data
} else {
reject(new Error(`Request failed with status code ${response.statusCode}`));
}
});
})
.on('error', error => {
reject(new Error(`Error making request: ${error.message}`)); // Reject on error
});
});
}

module.exports = { httpRequest };
55 changes: 1 addition & 54 deletions spec/test.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,9 @@ const filesAdapterTests = require('parse-server-conformance-tests').files;
const Parse = require('parse').Parse;
const S3Adapter = require('../index.js');
const optionsFromArguments = require('../lib/optionsFromArguments');
const {makeS3Adapter} = require("./mocks/s3adapter-v2.js");

describe('S3Adapter tests', () => {
function makeS3Adapter(options) {
let s3;

if (
process.env.TEST_S3_ACCESS_KEY
&& process.env.TEST_S3_SECRET_KEY
&& process.env.TEST_S3_BUCKET) {
// Should be initialized from the env
s3 = new S3Adapter(Object.assign({
accessKey: process.env.TEST_S3_ACCESS_KEY,
secretKey: process.env.TEST_S3_SECRET_KEY,
bucket: process.env.TEST_S3_BUCKET,
}, options));
} else {
const bucket = 'FAKE_BUCKET';

s3 = new S3Adapter('FAKE_ACCESS_KEY', 'FAKE_SECRET_KEY', bucket, options);

const objects = {};

s3._s3Client = {
createBucket: (callback) => setTimeout(callback, 100),
upload: (params, callback) => setTimeout(() => {
const { Key, Body } = params;

objects[Key] = Body;

callback(null, {
Location: `https://${bucket}.s3.amazonaws.com/${Key}`,
});
}, 100),
deleteObject: (params, callback) => setTimeout(() => {
const { Key } = params;

delete objects[Key];

callback(null, {});
}, 100),
getObject: (params, callback) => setTimeout(() => {
const { Key } = params;

if (objects[Key]) {
callback(null, {
Body: Buffer.from(objects[Key], 'utf8'),
});
} else {
callback(new Error('Not found'));
}
}, 100),
};
}
return s3;
}

beforeEach(() => {
delete process.env.S3_BUCKET;
delete process.env.S3_REGION;
Expand Down
Loading