[FIX] web: Make sample server tests deterministic

Before this commit, there were a few tests in the "sample server" suite
that asserted that every group resulting of a "read_group" would contain
at least one record, while there was actually a slight chance of it not
happening.

Now, the sample server used in the tests has been rendered deterministic
and these kind of issues are completely avoided.

closes odoo/odoo#54164

X-original-commit: a6d32ff46558b68ce3f19458f29c311ee5c658fd
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Julien Mougenot (jum) <jum@odoo.com>
This commit is contained in:
Julien Mougenot
2020-07-07 08:33:28 +00:00
parent e93b9aa271
commit cd1d339763
2 changed files with 120 additions and 56 deletions
+59 -13
View File
@@ -198,7 +198,7 @@ odoo.define('web.SampleServer', function (require) {
const field = this.data[modelName].fields[fieldName];
switch (field.type) {
case "boolean":
return fieldName === 'active' ? true : Math.random() < 0.5;
return fieldName === 'active' ? true : this._getRandomBool();
case "char":
case "text":
if (["display_name", "name"].includes(fieldName)) {
@@ -227,23 +227,22 @@ odoo.define('web.SampleServer', function (require) {
return false;
case "date":
case "datetime": {
const delta = Math.floor((Math.random() - Math.random()) * SampleServer.DATE_DELTA);
const date = new moment().add(delta, "hour").format(
field.type === "date" ? "YYYY-MM-DD" : "YYYY-MM-DD HH:mm:ss"
);
return date;
const format = field.type === "date" ?
"YYYY-MM-DD" :
"YYYY-MM-DD HH:mm:ss";
return this._getRandomDate(format);
}
case "float":
return Math.random() * SampleServer.MAX_FLOAT;
return this._getRandomFloat(SampleServer.MAX_FLOAT);
case "integer": {
let max = SampleServer.MAX_INTEGER;
if (fieldName.includes('color')) {
max = Math.random() < 0.5 ? SampleServer.MAX_COLOR_INT : 0;
max = this._getRandomBool() ? SampleServer.MAX_COLOR_INT : 0;
}
return Math.floor(Math.random() * max);
return this._getRandomInt(max);
}
case "monetary":
return Math.floor(Math.random() * SampleServer.MAX_MONETARY);
return this._getRandomInt(SampleServer.MAX_MONETARY);
case "many2one":
if (field.relation === 'res.currency') {
return session.company_currency_id;
@@ -256,8 +255,7 @@ odoo.define('web.SampleServer', function (require) {
}
case "selection": {
if (field.selection.length > 0) {
const index = Math.floor(Math.random() * field.selection.length);
return field.selection[index][0];
return this._getRandomArrayEl(field.selection)[0];
}
return false;
}
@@ -267,7 +265,55 @@ odoo.define('web.SampleServer', function (require) {
}
/**
* Generates a random id in the range of ids generated for sub models.
* @private
* @param {any[]} array
* @returns {any}
*/
_getRandomArrayEl(array) {
return array[Math.floor(Math.random() * array.length)];
}
/**
* @private
* @returns {boolean}
*/
_getRandomBool() {
return Math.random() < 0.5;
}
/**
* @private
* @param {string} format
* @returns {moment}
*/
_getRandomDate(format) {
const delta = Math.floor(
(Math.random() - Math.random()) * SampleServer.DATE_DELTA
);
return new moment()
.add(delta, "hour")
.format(format);
}
/**
* @private
* @param {number} max
* @returns {number} float in [O, max[
*/
_getRandomFloat(max) {
return Math.random() * max;
}
/**
* @private
* @param {number} max
* @returns {number} int in [0, max[
*/
_getRandomInt(max) {
return Math.floor(Math.random() * max);
}
/**
* @private
* @returns {number} id in [1, SUB_RECORDSET_SIZE]
*/
@@ -8,9 +8,31 @@ odoo.define('web.sample_server_tests', function (require) {
const {
MAIN_RECORDSET_SIZE, SEARCH_READ_LIMIT, // Limits
SAMPLE_COUNTRIES, SAMPLE_PEOPLE, SAMPLE_TEXTS, // Text values
MAX_COLOR_INT, MAX_FLOAT, MAX_INTEGER, MAX_MONETARY // Number values
MAX_COLOR_INT, MAX_FLOAT, MAX_INTEGER, MAX_MONETARY, // Number values
SUB_RECORDSET_SIZE, // Records sise
} = SampleServer;
/**
* Transforms random results into deterministic ones.
*/
class DeterministicSampleServer extends SampleServer {
constructor() {
super(...arguments);
this.arrayElCpt = 0;
this.boolCpt = 0;
this.subRecordIdCpt = 0;
}
_getRandomArrayEl(array) {
return array[this.arrayElCpt++ % array.length];
}
_getRandomBool() {
return Boolean(this.boolCpt++ % 2);
}
_getRandomSubRecordId() {
return (this.subRecordIdCpt++ % SUB_RECORDSET_SIZE) + 1;
}
}
QUnit.module("Sample Server", {
beforeEach() {
this.fields = {
@@ -62,7 +84,7 @@ odoo.define('web.sample_server_tests', function (require) {
});
const allFieldNames = Object.keys(this.fields['res.users']);
const server = new SampleServer('res.users', this.fields['res.users']);
const server = new DeterministicSampleServer('res.users', this.fields['res.users']);
const { records } = await server.mockRpc({
method: '/web/dataset/search_read',
model: 'res.users',
@@ -127,12 +149,12 @@ odoo.define('web.sample_server_tests', function (require) {
assert.strictEqual(typeof rec.manager_id[0], 'number');
assert.ok(SAMPLE_PEOPLE.includes(rec.manager_id[1]));
assert.ok([1, 2].includes(rec.managed_ids.length));
assert.strictEqual(rec.managed_ids.length, 2);
assert.ok(rec.managed_ids.every(
(id) => typeof id === 'number')
);
assert.ok([1, 2].includes(rec.tag_ids.length));
assert.strictEqual(rec.tag_ids.length, 2);
assert.ok(rec.tag_ids.every(
(id) => typeof id === 'number')
);
@@ -143,7 +165,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Sample data: country type", async function (assert) {
assert.expect(1);
const server = new SampleServer('res.country', this.fields['res.country']);
const server = new DeterministicSampleServer('res.country', this.fields['res.country']);
const { records } = await server.mockRpc({
method: '/web/dataset/search_read',
model: 'res.country',
@@ -156,7 +178,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Sample data: any type", async function (assert) {
assert.expect(1);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const { records } = await server.mockRpc({
method: '/web/dataset/search_read',
@@ -172,7 +194,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'search_read' RPC: valid field names", async function (assert) {
assert.expect(3);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: '/web/dataset/search_read',
@@ -193,7 +215,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'search_read' RPC: invalid field names", async function (assert) {
assert.expect(3);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: '/web/dataset/search_read',
@@ -214,7 +236,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'web_read_group' RPC: no group", async function (assert) {
assert.expect(1);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
server.setExistingGroups([]);
const result = await server.mockRpc({
@@ -227,9 +249,9 @@ odoo.define('web.sample_server_tests', function (require) {
});
QUnit.test("Send 'web_read_group' RPC: 2 groups", async function (assert) {
assert.expect(6);
assert.expect(5);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const existingGroups = [
{ profession: 'gardener', profession_count: 0 },
{ profession: 'adventurer', profession_count: 0 },
@@ -246,9 +268,10 @@ odoo.define('web.sample_server_tests', function (require) {
assert.strictEqual(result.length, 2);
assert.strictEqual(result.groups.length, 2);
const professions = result.groups.map((g) => g.profession);
assert.ok(professions.includes("gardener"));
assert.ok(professions.includes("adventurer"));
assert.deepEqual(
result.groups.map((g) => g.profession),
["gardener", "adventurer"]
);
assert.strictEqual(
result.groups.reduce((acc, g) => acc + g.profession_count, 0),
@@ -260,9 +283,9 @@ odoo.define('web.sample_server_tests', function (require) {
});
QUnit.test("Send 'web_read_group' RPC: all groups", async function (assert) {
assert.expect(7);
assert.expect(5);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const existingGroups = [
{ profession: 'gardener', profession_count: 0 },
{ profession: 'brewer', profession_count: 0 },
@@ -280,10 +303,10 @@ odoo.define('web.sample_server_tests', function (require) {
assert.strictEqual(result.length, 3);
assert.strictEqual(result.groups.length, 3);
const professions = result.groups.map((g) => g.profession);
assert.ok(professions.includes("gardener"));
assert.ok(professions.includes("brewer"));
assert.ok(professions.includes("adventurer"));
assert.deepEqual(
result.groups.map((g) => g.profession),
["gardener", "brewer", "adventurer"]
);
assert.strictEqual(
result.groups.reduce((acc, g) => acc + g.profession_count, 0),
@@ -297,7 +320,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read_group' RPC: no group", async function (assert) {
assert.expect(1);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read_group',
@@ -313,9 +336,9 @@ odoo.define('web.sample_server_tests', function (require) {
});
QUnit.test("Send 'read_group' RPC: groupBy", async function (assert) {
assert.expect(5);
assert.expect(3);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read_group',
@@ -325,12 +348,10 @@ odoo.define('web.sample_server_tests', function (require) {
});
assert.strictEqual(result.length, 3);
const professions = result.map((g) => g.profession);
assert.ok(professions.includes("gardener"));
assert.ok(professions.includes("brewer"));
assert.ok(professions.includes("adventurer"));
assert.deepEqual(
result.map((g) => g.profession),
["gardener", "brewer", "adventurer"]
);
assert.strictEqual(
result.reduce((acc, g) => acc + g.profession_count, 0),
MAIN_RECORDSET_SIZE,
@@ -338,9 +359,9 @@ odoo.define('web.sample_server_tests', function (require) {
});
QUnit.test("Send 'read_group' RPC: groupBy and field", async function (assert) {
assert.expect(6);
assert.expect(4);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read_group',
@@ -350,17 +371,14 @@ odoo.define('web.sample_server_tests', function (require) {
});
assert.strictEqual(result.length, 3);
const professions = result.map((g) => g.profession);
assert.ok(professions.includes("gardener"));
assert.ok(professions.includes("brewer"));
assert.ok(professions.includes("adventurer"));
assert.deepEqual(
result.map((g) => g.profession),
["gardener", "brewer", "adventurer"]
);
assert.strictEqual(
result.reduce((acc, g) => acc + g.profession_count, 0),
MAIN_RECORDSET_SIZE,
);
assert.strictEqual(
result.reduce((acc, g) => acc + g.age, 0),
server.data.hobbit.records.reduce((acc, g) => acc + g.age, 0)
@@ -370,7 +388,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read_group' RPC: multiple groupBys and lazy", async function (assert) {
assert.expect(2);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read_group',
@@ -386,7 +404,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read_group' RPC: multiple groupBys and not lazy", async function (assert) {
assert.expect(2);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read_group',
@@ -403,7 +421,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read' RPC: no id", async function (assert) {
assert.expect(1);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read',
@@ -419,7 +437,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read' RPC: one id", async function (assert) {
assert.expect(3);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const result = await server.mockRpc({
method: 'read',
@@ -440,7 +458,7 @@ odoo.define('web.sample_server_tests', function (require) {
QUnit.test("Send 'read' RPC: more than all available ids", async function (assert) {
assert.expect(1);
const server = new SampleServer('hobbit', this.fields.hobbit);
const server = new DeterministicSampleServer('hobbit', this.fields.hobbit);
const amount = MAIN_RECORDSET_SIZE + 3;
const ids = new Array(amount).fill().map((_, i) => i + 1);