mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-29 00:08:11 +08:00
Jest tests for part of util/stateManager * reorganize test directories * lint * add Jest config to eslint * add Jest config to eslint * lint * fix babel configuration for tests * start at kvCache tests * reorganize test directories * lint * add Jest config to eslint * add Jest config to eslint * lint * fix babel configuration for tests * start at kvCache tests * fix cache flush bug manifest by new test cases * new kvCache tests * skeletal universe test * fix race in test case * more universe test cases
231 lines
5.7 KiB
JavaScript
231 lines
5.7 KiB
JavaScript
/* eslint no-bitwise: "off" */
|
|
|
|
import _ from "lodash";
|
|
import * as Universe from "../../../src/util/stateManager/universe";
|
|
|
|
/*
|
|
test data mocking REST 0.2 API responses
|
|
*/
|
|
const nObs = 10;
|
|
const nVar = 32;
|
|
const field4Categories = [83, true, "foo", 2.222222];
|
|
const fieldDCategories = [99, false, "mumble", 3.1415];
|
|
|
|
const aConfigResponse = {
|
|
config: {
|
|
features: [
|
|
{ method: "POST", path: "/cluster/", available: false },
|
|
{ method: "POST", path: "/layout/", available: false },
|
|
{ method: "POST", path: "/diffexp/", available: false },
|
|
{ method: "POST", path: "/saveLocal/", available: false }
|
|
],
|
|
displayNames: {
|
|
engine: "the little engine that could",
|
|
dataset: "all your zeros are mine"
|
|
}
|
|
}
|
|
};
|
|
|
|
const aSchemaResponse = {
|
|
schema: {
|
|
dataframe: {
|
|
nObs,
|
|
nVar,
|
|
type: "float32"
|
|
},
|
|
annotations: {
|
|
obs: [
|
|
{ name: "name", type: "string" },
|
|
{ name: "field1", type: "int32" },
|
|
{ name: "field2", type: "float32" },
|
|
{ name: "field3", type: "boolean" },
|
|
{
|
|
name: "field4",
|
|
type: "categorical",
|
|
categories: field4Categories
|
|
}
|
|
],
|
|
var: [
|
|
{ name: "name", type: "string" },
|
|
{ name: "fieldA", type: "int32" },
|
|
{ name: "fieldB", type: "float32" },
|
|
{ name: "fieldC", type: "boolean" },
|
|
{
|
|
name: "fieldD",
|
|
type: "categorical",
|
|
categories: fieldDCategories
|
|
}
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
const anAnnotationsObsResponse = {
|
|
names: ["name", "field1", "field2", "field3", "field4"],
|
|
data: _()
|
|
.range(nObs)
|
|
.map(idx => [
|
|
idx,
|
|
`obs${idx}`,
|
|
2 * idx,
|
|
idx + 0.0133,
|
|
idx & 1,
|
|
field4Categories[idx % field4Categories.length]
|
|
])
|
|
.value()
|
|
};
|
|
|
|
const anAnnotationsVarResponse = {
|
|
names: ["fieldA", "fieldB", "fieldC", "fieldD", "name"],
|
|
data: _()
|
|
.range(nVar)
|
|
.map(idx => [
|
|
idx,
|
|
10 * idx,
|
|
idx + 2.90143,
|
|
idx & 1,
|
|
fieldDCategories[idx % fieldDCategories.length],
|
|
`var${idx}`
|
|
])
|
|
.value()
|
|
};
|
|
|
|
const aLayoutResponse = {
|
|
layout: {
|
|
ndims: 2,
|
|
coordinates: _()
|
|
.range(nObs)
|
|
.map(idx => [idx, Math.random(), Math.random()])
|
|
.value()
|
|
}
|
|
};
|
|
|
|
const aDataObsResponse = {
|
|
var: [2, 4, 29],
|
|
obs: _()
|
|
.range(nObs)
|
|
.map(idx => [idx, Math.random(), Math.random(), Math.random()])
|
|
.value()
|
|
};
|
|
|
|
describe("createUniverseFromRestV02Response", () => {
|
|
/*
|
|
test createUniverseFromRestV02Response - this function converts
|
|
a set of REST 0.2 responses into a "new" Universe.
|
|
|
|
createUniverseFromRestV02Response(
|
|
configResponse,
|
|
schemaResponse,
|
|
annotationsObsResponse,
|
|
annotationsVarResponse,
|
|
layoutObsResponse
|
|
) --> Universe
|
|
|
|
where:
|
|
configResponse: GET /.../config
|
|
schemaResponse: GET /.../schema
|
|
annotationsObsResponse: GET /.../annotations/obs
|
|
annotationsVarResponse: GET /.../annotations/var
|
|
layoutObsResponse: GET /.../layout/obs
|
|
|
|
See spec in docs/REST_API.md.
|
|
*/
|
|
|
|
test("create from test data", () => {
|
|
/*
|
|
create a universe from sample data nad validate its shape & contents
|
|
*/
|
|
|
|
const universe = Universe.createUniverseFromRestV02Response(
|
|
aConfigResponse,
|
|
aSchemaResponse,
|
|
anAnnotationsObsResponse,
|
|
anAnnotationsVarResponse,
|
|
aLayoutResponse
|
|
);
|
|
|
|
expect(universe).toBeDefined();
|
|
expect(universe).toMatchObject(
|
|
expect.objectContaining({
|
|
api: "0.2",
|
|
nObs,
|
|
nVar,
|
|
schema: aSchemaResponse.schema,
|
|
obsAnnotations: expect.any(Array),
|
|
varAnnotations: expect.any(Array),
|
|
obsNameToIndexMap: expect.any(Object),
|
|
varNameToIndexMap: expect.any(Object),
|
|
obsLayout: expect.objectContaining({
|
|
X: expect.any(Float32Array),
|
|
Y: expect.any(Float32Array)
|
|
}),
|
|
varDataCache: expect.any(Object)
|
|
})
|
|
);
|
|
|
|
expect(_.size(universe.obsAnnotations)).toBe(nObs);
|
|
expect(_.size(universe.obsNameToIndexMap)).toBe(nObs);
|
|
expect(_.size(universe.obsLayout.X)).toBe(nObs);
|
|
expect(_.size(universe.obsLayout.Y)).toBe(nObs);
|
|
expect(_.size(universe.varAnnotations)).toBe(nVar);
|
|
expect(_.size(universe.varNameToIndexMap)).toBe(nVar);
|
|
});
|
|
});
|
|
|
|
describe("convertExpressionRESTv02ToObject", () => {
|
|
/*
|
|
test convertExpressionRESTv02ToObject
|
|
|
|
convertExpressionRESTv02ToObject(
|
|
universe,
|
|
response) --> { geneName: Float32Array, geneName: Float32Array, ... }
|
|
|
|
reponse is a /data/obs response:
|
|
{
|
|
var: [ varIndices fetched ],
|
|
obs: [
|
|
[ obsIndex, evalue, ... ],
|
|
...
|
|
]
|
|
}
|
|
*/
|
|
test("create from response data", () => {
|
|
const universe = Universe.createUniverseFromRestV02Response(
|
|
aConfigResponse,
|
|
aSchemaResponse,
|
|
anAnnotationsObsResponse,
|
|
anAnnotationsVarResponse,
|
|
aLayoutResponse
|
|
);
|
|
const expression = Universe.convertExpressionRESTv02ToObject(
|
|
universe,
|
|
aDataObsResponse
|
|
);
|
|
|
|
/* Check that the expected keys are present */
|
|
const expectedGeneNames = _.map(
|
|
aDataObsResponse.var,
|
|
v => anAnnotationsVarResponse.data[v][5]
|
|
);
|
|
expect(Object.keys(expression)).toEqual(
|
|
expect.arrayContaining(expectedGeneNames)
|
|
);
|
|
|
|
const expectedExpressionValues = _.map(
|
|
_.unzip(aDataObsResponse.obs),
|
|
a => new Float32Array(a)
|
|
);
|
|
|
|
// console.log(aDataObsResponse);
|
|
// console.log(expression);
|
|
// console.log(_.unzip(aDataObsResponse.obs));
|
|
|
|
_.forEach(aDataObsResponse.var, (varIdx, idx) => {
|
|
const varName = universe.varAnnotations[varIdx].name;
|
|
expect(varName).toBeDefined();
|
|
expect(varIdx).toBe(universe.varNameToIndexMap[varName]);
|
|
expect(expression[varName]).toEqual(expectedExpressionValues[idx + 1]);
|
|
});
|
|
});
|
|
});
|