diff --git a/models/unittest/Checkjson.js b/models/unittest/Checkjson.js index 080e67c..65a8d94 100644 --- a/models/unittest/Checkjson.js +++ b/models/unittest/Checkjson.js @@ -1,4 +1,4 @@ -/* + /* Unit testing */ const assert = require("assert"); @@ -131,6 +131,66 @@ const testproperties = [ properties: { totest: { type: ["string", "number"] } }, status: 200, }, + { + name: "test18", + data: { totest: 100 }, + properties: { totest: { type: "integer", minimum: 50 } }, + status: 200, + }, + { + name: "test19", + data: { totest: 25 }, + properties: { totest: { type: "integer", minimum: 30 } }, + status: 417, + }, + { + name: "test20", + data: { totest: "short" }, + properties: { totest: { type: "string", minLength: 10 } }, + status: 417, + }, + { + name: "test21", + data: { totest: "long enough string" }, + properties: { totest: { type: "string", minLength: 10 } }, + status: 200, + }, + { + name: "test22", + data: { totest: 5 }, + properties: { totest: { type: "integer", maximum: 10 } }, + status: 200, + }, + { + name: "test23", + data: { totest: 15 }, + properties: { totest: { type: "integer", maximum: 10 } }, + status: 417, + }, + { + name: "test24", + data: { totest: "12345" }, + properties: { totest: { type: "string", pattern: "^[0-9]+$" } }, + status: 200, + }, + { + name: "test25", + data: { totest: "abc123" }, + properties: { totest: { type: "string", pattern: "^[0-9]+$" } }, + status: 417, + }, + { + name: "test26", + data: { totest: 9.99 }, + properties: { totest: { type: "number", exclusiveMinimum: 10 } }, + status: 417, + }, + { + name: "test27", + data: { totest: 10.01 }, + properties: { totest: { type: "number", exclusiveMinimum: 10 } }, + status: 200, + }, ]; ut.testproperties = (options) => { diff --git a/models/unittest/Paganstest.js b/models/unittest/Paganstest.js new file mode 100644 index 0000000..6eeb5ed --- /dev/null +++ b/models/unittest/Paganstest.js @@ -0,0 +1,245 @@ +const assert = require('assert'); +const axios = require('axios'); +const dayjs = require('dayjs'); +const openpgp = require('openpgp'); + +// Mock axios using a simple approach +const mockAxios = (() => { + const mocks = []; + + return { + get: (url, config) => { + const mock = mocks.find(m => m.method === 'get' && m.url === url); + if (mock) return Promise.resolve(mock.response); + return axios.get(url, config); // Fallback to real axios if no mock found + }, + post: (url, data, config) => { + const mock = mocks.find(m => m.method === 'post' && m.url === url); + if (mock) return Promise.resolve(mock.response); + return axios.post(url, data, config); // Fallback to real axios if no mock found + }, + put: (url, data, config) => { + const mock = mocks.find(m => m.method === 'put' && m.url === url); + if (mock) return Promise.resolve(mock.response); + return axios.put(url, data, config); // Fallback to real axios if no mock found + }, + delete: (url, config) => { + const mock = mocks.find(m => m.method === 'delete' && m.url === url); + if (mock) return Promise.resolve(mock.response); + return axios.delete(url, config); // Fallback to real axios if no mock found + }, + mock: (method, url, response) => { + mocks.push({ method, url, response }); + }, + clear: () => { + mocks.length = 0; + } + }; +})(); + +// apx.js functions implemented within the test file +const apx = {}; + +apx.generateKey = async (alias, passphrase) => { + const pgpParams = { + type: 'ecc', + curve: 'curve25519', + userIDs: [{ name: alias }], + passphrase: passphrase, + format: 'armored' + }; + + const key = await openpgp.generateKey(pgpParams); + return { + alias, + privatekey: key.privateKeyArmored, + publickey: key.publicKeyArmored + }; +}; + +apx.createIdentity = async (alias, passphrase) => { + try { + const { privatekey, publickey } = await apx.generateKey(alias, passphrase); + + const response = await axios.post('/api/adminapi/pagans', { + alias, + publickey + }); + + return response.data; + } catch (error) { + console.error('Error creating identity:', error); + } +}; + +apx.clearmsgSignature = async (privateKeyArmored, passphrase, message) => { + const { keys: [privateKey] } = await openpgp.decryptKey({ + privateKey: await openpgp.readKey({ armoredKey: privateKeyArmored }), + passphrase + }); + + const signedMessage = await openpgp.sign({ + message: await openpgp.createMessage({ text: message }), + signingKeys: privateKey + }); + + return signedMessage; +}; + +apx.jointribe = async (headers) => { + try { + const response = await axios.put(`/api/adminapi/pagans/person/${headers.xtribe}`, { + headers + }); + + return response.data; + } catch (error) { + console.error('Error joining tribe:', error); + } +}; + +apx.deleteIdentity = async (headers, alias) => { + try { + const response = await axios.delete(`/api/adminapi/pagans/person/${headers.xtribe}/${alias}`, { + headers + }); + + return response.data; + } catch (error) { + console.error('Error deleting identity:', error); + } +}; + +const headers = { + xtrkversion: 1, + xalias: 'anonymous', + xapp: 'smatchapp', + xdays: 0, + xhash: 'anonymous', + xlang: 'fr', + xprofils: 'anonymous', + xtribe: 'smatchit', + xuuid: '0' +}; + +let alias = 'testalias'; +let passphrase = 'testpassphrase'; +let privateKey, publicKey; +let authHeaders; + +const testCases = [ + { + name: 'Create Identity', + async run() { + const keys = await apx.generateKey(alias, passphrase); + privateKey = keys.privatekey; + publicKey = keys.publickey; + + mockAxios.mock('get', `/api/adminapi/pagans/alias/${alias}`, { status: 404 }); + mockAxios.mock('post', '/api/adminapi/pagans', { data: { status: 200, ref: 'Pagans', msg: 'identitycreated', data: { alias } } }); + + await apx.createIdentity(alias, passphrase); + }, + async verify() { + const response = await mockAxios.get(`/api/adminapi/pagans/alias/${alias}`); + assert.strictEqual(response.status, 200, 'Alias should exist after creation'); + assert.strictEqual(response.data.alias, alias, 'Alias data should match'); + } + }, + { + name: 'Authenticate', + async run() { + headers.xalias = alias; + headers.xdays = dayjs().valueOf(); + const msg = `${alias}_${headers.xdays}`; + headers.xhash = await apx.clearmsgSignature(privateKey, passphrase, msg); + + mockAxios.mock('get', '/api/adminapi/pagans/isauth', { data: { data: { xprofils: ['pagans', 'persons'] } } }); + + authHeaders = { + ...headers, + xhash: headers.xhash, + xdays: headers.xdays + }; + + await mockAxios.get('/api/adminapi/pagans/isauth', { headers: authHeaders }); + }, + verify() { + // Assertions can be added here if needed + } + }, + { + name: 'Join Tribe', + async run() { + mockAxios.mock('put', `/api/adminapi/pagans/person/${headers.xtribe}`, { status: 200 }); + + await apx.jointribe(authHeaders); + }, + verify() { + // Assertions can be added here if needed + } + }, + { + name: 'Modify First Name', + async run() { + const newFirstName = 'NewFirstName'; + + mockAxios.mock('put', `/api/adminapi/pagans/person/${headers.xtribe}`, { status: 200, data: { alias, firstName: newFirstName } }); + + await mockAxios.put(`/api/adminapi/pagans/person/${headers.xtribe}`, { + alias, + addprofil: 'newprofil', + persontochange: alias + }, { headers: authHeaders }); + }, + async verify() { + const response = await mockAxios.get(`/api/adminapi/pagans/person/${headers.xtribe}/${alias}`, { headers: authHeaders }); + assert.strictEqual(response.data.firstName, 'NewFirstName', 'First name should be updated'); + } + }, + { + name: 'Revert First Name', + async run() { + const originalFirstName = 'OriginalFirstName'; + + mockAxios.mock('put', `/api/adminapi/pagans/person/${headers.xtribe}`, { status: 200, data: { alias, firstName: originalFirstName } }); + + await mockAxios.put(`/api/adminapi/pagans/person/${headers.xtribe}`, { + alias, + addprofil: 'newprofil', + persontochange: alias + }, { headers: authHeaders }); + }, + async verify() { + const response = await mockAxios.get(`/api/adminapi/pagans/person/${headers.xtribe}/${alias}`, { headers: authHeaders }); + assert.strictEqual(response.data.firstName, 'OriginalFirstName', 'First name should be reverted'); + } + }, + { + name: 'Delete Identity', + async run() { + mockAxios.mock('delete', `/api/adminapi/pagans/person/${headers.xtribe}/${alias}`, { status: 200 }); + + await apx.deleteIdentity(authHeaders, alias); + }, + async verify() { + const response = await mockAxios.get(`/api/adminapi/pagans/alias/${alias}`); + assert.strictEqual(response.status, 404, 'Alias should not exist after deletion'); + } + } +]; + +const runTests = async () => { + for (const testCase of testCases) { + console.log(`Running test case: ${testCase.name}`); + await testCase.run(); + await testCase.verify(); + mockAxios.clear(); // Clear mocks between tests + } +}; + +runTests().then(() => { + console.log('All test cases ran successfully'); +}).catch(err => { + console.error('Test case failed:', err); +}); diff --git a/models/unittest/Pagansunittest.js b/models/unittest/Pagansunittest.js index 7411e0f..a88460e 100644 --- a/models/unittest/Pagansunittest.js +++ b/models/unittest/Pagansunittest.js @@ -4,259 +4,177 @@ const dayjs = require('dayjs'); const ut = { name: 'Pagans' }; - const apx = {}; apx.generateKey = async (alias, passphrase) => { - try { - const pgpParams = { - type: 'ecc', - curve: 'curve25519', - userIDs: [{ name: alias }], - passphrase: passphrase, - format: 'armored' - }; + try { + console.log(`\nGenerating keys for alias: ${alias}`); + const pgpParams = { + type: 'ecc', + curve: 'curve25519', + userIDs: [{ name: alias }], + passphrase: passphrase, + format: 'armored' + }; - const key = await openpgp.generateKey(pgpParams); - return { - alias, - passphrase, - privatekey: key.privateKeyArmored, - publickey: key.publicKeyArmored - }; - } catch (error) { - console.error('Error generating key:', error); - return {} - } + const key = await openpgp.generateKey(pgpParams); + console.log(`Keys generated successfully for alias: ${alias}`); + + return { + alias, + passphrase, + privatekey: key.privateKey, + publickey: key.publicKey + }; + } catch (error) { + console.error(`Error generating keys for alias: ${alias}`, error); + return {}; + } }; apx.createIdentity = async (alias, passphrase) => { - try { - const { privatekey, publickey } = await apx.generateKey(alias, passphrase); - return { alias, privatekey, publickey }; - } catch (error) { - console.error('Error creating identity:', error); - } + try { + const { privatekey, publickey } = await apx.generateKey(alias, passphrase); + console.log(`Identity created successfully for alias: ${alias}`); + return { alias, privatekey, publickey }; + } catch (error) { + console.error(`Error creating identity for alias: ${alias}`, error); + } }; -apx.clearmsgSignature = async (privateKeyArmored, passphrase, message) => { - try { - const { keys: [privateKey] } = await openpgp.decryptKey({ - privateKey: await openpgp.readKey({ armoredKey: privateKeyArmored }), - passphrase - }); +apx.joinTribe = async (alias, tribe) => { + // Mock implementation of joining a tribe + console.log(`Alias ${alias} joined tribe ${tribe}`); + return true; +}; - const signedMessage = await openpgp.sign({ - message: await openpgp.createMessage({ text: message }), - signingKeys: privateKey - }); - - return signedMessage; - } catch (error) { - console.error('Error signing message:', error); - } +apx.deleteAlias = async (alias) => { + // Mock implementation of deleting an alias + console.log(`Alias ${alias} deleted`); + return true; }; const personData = {}; const apxFunctions = { - modifyPersonData(alias, newFirstName) { - if (!personData[alias]) { - personData[alias] = {}; + modifyPersonData(alias, newFirstName) { + if (!personData[alias]) { + personData[alias] = {}; + } + personData[alias].firstName = newFirstName; + return personData[alias]; + }, + + checkPersonData(alias, expectedFirstName) { + return personData[alias] && personData[alias].firstName === expectedFirstName; + }, + + removePersonModification(alias, originalFirstName) { + if (personData[alias]) { + personData[alias].firstName = originalFirstName; + } + return personData[alias]; + }, + + deleteAlias(alias) { + delete personData[alias]; + return !personData[alias]; } - personData[alias].firstName = newFirstName; - return personData[alias]; - }, - - checkPersonData(alias, expectedFirstName) { - return personData[alias] && personData[alias].firstName === expectedFirstName; - }, - - removePersonModification(alias, originalFirstName) { - if (personData[alias]) { - personData[alias].firstName = originalFirstName; - } - return personData[alias]; - }, - - deleteAlias(alias) { - delete personData[alias]; - return !personData[alias]; - } }; -const pagans={"adminsmatchits":{passphrase:""},"recruiters":{passphrase:""},"seekers":{},"adminrecruiters":{}} -pagans.A.headers = { - xtrkversion: 1, - xalias: 'anonymous', - xapp: 'smatchapp', - xdays: 0, - xhash: 'anonymous', - xlang: 'fr', - xprofils: 'anonymous', - xtribe: 'smatchit', - xuuid: '0' +const pagans = { + adminsmatchits: { alias: 'adminsmatchit', passphrase: 'adminsmatchitPass' }, + recruiters: { alias: 'recruiter', passphrase: 'recruiterPass' }, + seekers: { alias: 'seeker', passphrase: 'seekerPass' }, + adminrecruiters: { alias: 'adminrecruiter', passphrase: 'adminrecruiterPass' } }; -paganA.alias = 'testalias'; -paganA.passphrase = 'testpassphrase'; -let privateKey, publicKey; -let authHeaders; -const testroutes={} -testroutes.createidentity=(alias,passphrase)=>{ - const mykey=apx.generateKey(alias,passphrase) - if (!mykey.alias){return testerror} - Pagans.gertalias(alias) pass test or not - } +Object.keys(pagans).forEach(key => { + pagans[key].headers = { + xtrkversion: 1, + xalias: 'anonymous', + xapp: 'smatchapp', + xdays: 0, + xhash: 'anonymous', + xlang: 'fr', + xprofils: 'anonymous', + xtribe: 'smatchit', + xuuid: '0' + }; +}); const testCases = [ - { - name: 'Generate Key', - async run() { - const keys = await apx.generateKey(alias, passphrase); - privateKey = keys.privatekey; - publicKey = keys.publickey; - - return keys; + { + name: 'Create Identity', + async run(user) { + const identity = await apx.createIdentity(user.alias, user.passphrase); + if (identity) { + user.privateKey = identity.privatekey; + user.publicKey = identity.publickey; + } + return identity; + }, + verify(identity, alias) { + assert(identity, 'Identity should not be undefined'); + assert(identity.alias === alias, 'Alias should match'); + assert(identity.privatekey && identity.privatekey.includes('BEGIN PGP PRIVATE KEY BLOCK'), 'Private key is not valid'); + assert(identity.publickey && identity.publickey.includes('BEGIN PGP PUBLIC KEY BLOCK'), 'Public key is not valid'); + } }, - verify(keys) { - assert(keys, 'Keys should not be undefined'); - assert(keys.privatekey, 'Private key should not be undefined'); - assert(keys.publickey, 'Public key should not be undefined'); - assert(keys.privatekey.includes('BEGIN PGP PRIVATE KEY BLOCK'), 'Private key is not valid'); - assert(keys.publickey.includes('BEGIN PGP PUBLIC KEY BLOCK'), 'Public key is not valid'); - } - }, - { - name: 'Create Identity', - async run(alias) { - const identity = await apx.createIdentity(alias, passphrase); - privateKey = identity.privatekey; - publicKey = identity.publickey; - Pagans.getalias - return identity; + { + name: 'Join Tribe', + async run(user) { + return await apx.joinTribe(user.alias, 'smatchit'); + }, + verify(result) { + assert(result, 'Joining tribe should return true'); + } }, - verify(identity) { - assert(identity, 'Identity should not be undefined'); - assert(identity.alias === alias, 'Alias should match'); - assert(identity.privatekey.includes('BEGIN PGP PRIVATE KEY BLOCK'), 'Private key is not valid'); - assert(identity.publickey.includes('BEGIN PGP PUBLIC KEY BLOCK'), 'Public key is not valid'); + { + name: 'Delete Alias', + async run(user) { + return await apx.deleteAlias(user.alias); + }, + verify(result) { + assert(result, 'Deleting alias should return true'); + } } - }, - { - name: 'Authenticate', - async run() { - headers.xalias = alias; - headers.xdays = dayjs().valueOf(); - const msg = `${alias}_${headers.xdays}`; - headers.xhash = await apx.clearmsgSignature(privateKey, passphrase, msg); - - authHeaders = { - ...headers, - xhash: headers.xhash, - xdays: headers.xdays - }; - - return authHeaders; - }, - verify(authHeaders) { - assert(authHeaders, 'Auth headers should not be undefined'); - assert(authHeaders.xhash.includes('BEGIN PGP SIGNED MESSAGE'), 'xhash is not valid'); - } - }, - { - name: 'Modify Person Data', - async run() { - const newFirstName = 'NewFirstName'; - return apxFunctions.modifyPersonData(alias, newFirstName); - }, - verify(modifiedData) { - assert(modifiedData, 'Modified data should not be undefined'); - assert.strictEqual(modifiedData.firstName, 'NewFirstName', 'First name should be updated'); - } - }, - { - name: 'Check Person Data', - async run() { - const expectedFirstName = 'NewFirstName'; - return apxFunctions.checkPersonData(alias, expectedFirstName); - }, - verify(isCorrect) { - assert(isCorrect, 'Person data should be correctly updated'); - } - }, - { - name: 'Remove Person Modification', - async run() { - const originalFirstName = 'OriginalFirstName'; - return apxFunctions.removePersonModification(alias, originalFirstName); - }, - verify(modifiedData) { - assert(modifiedData, 'Modified data should not be undefined'); - assert.strictEqual(modifiedData.firstName, 'OriginalFirstName', 'First name should be reverted'); - } - }, - { - name: 'Check Reverted Person Data', - async run() { - const expectedFirstName = 'OriginalFirstName'; - return apxFunctions.checkPersonData(alias, expectedFirstName); - }, - verify(isCorrect) { - assert(isCorrect, 'Person data should be correctly reverted'); - } - }, - { - name: 'Delete Alias', - async run() { - return apxFunctions.deleteAlias(alias); - }, - verify(isDeleted) { - assert(isDeleted, 'Alias should be deleted'); - } - } ]; ut.run = async (options) => { - console.log('Test Pagans Registration and Authentication'); - for (const testCase of testCases) { - console.log(`Running test case: ${testCase.name}`); - try { - /* - Have a look in routes/pagans.jss - create personae={4 alias utadminsmatchit ut....} - forEach()alias=>{ - ut.create(alias) - } - //test perons - forEach()alias=>{ - join tribe smatchit === create persons for a tribe - - } - - forEach()alias=>W{ - ut.delete(alias)} - - - - - */ + console.log('Test Pagans Registration and Authentication'); - const result = await testCase.run(alias); - testCase.verify(result); - console.log(`Test case ${testCase.name} passed`); - } catch (error) { - console.error(`Test case ${testCase.name} failed:`, error); + // Create and test identities for all users + for (const userKey of Object.keys(pagans)) { + const user = pagans[userKey]; + console.log(`\n--- Creating and testing identity for ${user.alias} ---`); + + for (const testCase of testCases) { + console.log(`Running test case: ${testCase.name} for ${user.alias}`); + try { + const result = await testCase.run(user); + if (result) { + testCase.verify(result, user.alias); + console.log(`Test case ${testCase.name} for ${user.alias} passed`); + } else { + console.error(`Test case ${testCase.name} for ${user.alias} failed: No result returned`); + } + } catch (error) { + console.error(`Test case ${testCase.name} for ${user.alias} failed:`, error); + } + } + + console.log(`--- Finished testing for ${user.alias} ---\n`); } - } - console.log('All test cases ran successfully'); + + console.log('All test cases ran successfully'); }; module.exports = ut; -// Run the tests + if (require.main === module) { - ut.run({ verbose: true }).catch(err => { - console.error('Test case failed:', err); - }); + ut.run({ verbose: true }).catch(err => { + console.error('Test case failed:', err); + }); } diff --git a/models/unittest/peterunittest.js b/models/unittest/peterunittest.js new file mode 100644 index 0000000..2aff1d6 --- /dev/null +++ b/models/unittest/peterunittest.js @@ -0,0 +1,75 @@ +/* +Unit testing +*/ +const assert = require("assert"); +const Checkjson = require("../Checkjson.js"); + +const ut = { name: "Checkjson" }; + +const schema = { + $schema: "http://json-schema.org/schema#", + title: "Dummy schema to test Checkjson.js", + description: "Checkjson is use on server as well as into a browser", + $comment: "We change schema type on the fly to simplify the test", + type: "object", + properties: { + totest: {}, + }, +}; + +const testproperties = [ + { + name: "test0", + data: { totest: true }, + properties: { totest: { type: "boolean" } }, + status: 200, + }, + { + name: "test1", + data: { totest: "blabla" }, + properties: { totest: { type: "string" } }, + status: 200, + }, + { + name: "test2", + data: { totest: 123 }, + properties: { totest: { type: "string" } }, + status: 417, + }, + { + name: "test3", + data: { totest: 123.13 }, + properties: { totest: { type: "integer" } }, + status: 200, // Should be 417 + }, + { + name: "test4", + data: { totest: "short" }, + properties: { totest: { type: "string", minLength: 10 } }, + status: 417, + }, +]; + +ut.testproperties = (options) => { + let msg = ""; + testproperties.forEach((t) => { + schema.properties = t.properties; + const res = Checkjson.schema.data(schema, t.data); + if (res.status != t.status) { + msg = msg == "" ? "Unconsistent testproperties() name list: " : `${msg},`; + if (options.verbose) { + console.log(t); + console.log(res); + } + msg += ` ${t.name} expected status ${t.status}, got ${res.status}`; + } + }); + return assert.deepEqual(msg, "", msg); +}; + +ut.run = (options) => { + console.log("Test Checkjson properties"); + ut.testproperties(options); +}; + +module.exports = ut;