terriajs
Version:
Geospatial data visualization platform.
340 lines (302 loc) • 11.5 kB
JavaScript
;
import CesiumEvent from "terriajs-cesium/Source/Core/Event";
import ImageryLayer from "terriajs-cesium/Source/Scene/ImageryLayer";
import ImageryProvider from "terriajs-cesium/Source/Scene/ImageryProvider";
import ImageryState from "terriajs-cesium/Source/Scene/ImageryState";
import JulianDate from "terriajs-cesium/Source/Core/JulianDate";
import pollToPromise from "../../lib/Core/pollToPromise";
import RequestErrorEvent from "terriajs-cesium/Source/Core/RequestErrorEvent";
import Resource from "terriajs-cesium/Source/Core/Resource";
import runLater from "../../../../lib/Core/runLater";
import TimeIntervalCollection from "terriajs-cesium/Source/Core/TimeIntervalCollection";
import TimeInterval from "terriajs-cesium/Source/Core/TimeInterval";
import Terria from "../../../../lib/Models/Terria";
import ImageryLayerCatalogItem from "../../lib/Models/ImageryLayerCatalogItem";
describe("ImageryLayerCatalogItem", function () {
describe("Time slider initial time as specified by initialTimeSource ", function () {
var terria;
var catalogItem;
beforeEach(function () {
terria = new Terria({
baseUrl: "./"
});
catalogItem = new ImageryLayerCatalogItem(terria);
});
// Future developers take note: some of these tests will stop working in August 3015.
it('should be start if "start" set', function () {
catalogItem.initialTimeSource = "start";
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-07T00:00:00.00Z"),
stop: JulianDate.fromIso8601("2015-08-09T00:00:00.00Z")
})
]);
var currentTime = JulianDate.toIso8601(catalogItem.clock.currentTime, 3);
// Do not compare time, because on some systems the second could have ticked over between getting the two times.
currentTime = currentTime.substr(0, 10);
expect(currentTime).toBe("2013-08-07");
});
it('should be current time if "present" set', function () {
catalogItem.initialTimeSource = "present";
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-07T00:00:00.00Z"),
stop: JulianDate.fromIso8601("3115-08-09T00:00:00.00Z")
})
]);
var dateNow = new Date().toISOString();
var currentTime = JulianDate.toIso8601(catalogItem.clock.currentTime, 3);
// Do not compare time, because on some systems the second could have ticked over between getting the two times.
dateNow = dateNow.substr(0, 10);
currentTime = currentTime.substr(0, 10);
expect(currentTime).toBe(dateNow);
});
it('should be last time if "end" set', function () {
catalogItem.initialTimeSource = "end";
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-07T00:00:00.00Z"),
stop: JulianDate.fromIso8601("2015-08-09T00:00:00.00Z")
})
]);
var currentTime = JulianDate.toIso8601(catalogItem.clock.currentTime, 3);
// Do not compare time, because on some systems the second could have ticked over between getting the two times.
currentTime = currentTime.substr(0, 10);
expect(currentTime).toBe("2015-08-09");
});
it("should be set to date specified if date is specified", function () {
catalogItem.initialTimeSource = "2015-08-08T00:00:00.00Z";
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-07T00:00:00.00Z"),
stop: JulianDate.fromIso8601("2015-08-11T00:00:00.00Z")
})
]);
var currentTime = JulianDate.toIso8601(catalogItem.clock.currentTime, 3);
// Do not compare time, because on some systems the second could have ticked over between getting the two times.
currentTime = currentTime.substr(0, 10);
expect(currentTime).toBe("2015-08-08");
});
it("should be set to start if date specified is before time range, with two intervals", function () {
catalogItem.initialTimeSource = "2012-01-01T12:00:00Z";
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-01T15:00:00Z"),
stop: JulianDate.fromIso8601("2013-08-01T18:00:00Z")
}),
new TimeInterval({
start: JulianDate.fromIso8601("2013-09-01T11:00:00Z"),
stop: JulianDate.fromIso8601("2013-09-03T13:00:00Z")
})
]);
var currentTime = JulianDate.toIso8601(catalogItem.clock.currentTime, 3);
// Do not compare time, because on some systems the second could have ticked over between getting the two times.
currentTime = currentTime.substr(0, 10);
expect(currentTime).toBe("2013-08-01");
});
it("should throw if a rubbish string is specified", function () {
catalogItem.initialTimeSource = "2015z08-08";
expect(function () {
catalogItem.intervals = new TimeIntervalCollection([
new TimeInterval({
start: JulianDate.fromIso8601("2013-08-07T00:00:00.00Z"),
stop: JulianDate.fromIso8601("2115-08-09T00:00:00.00Z")
})
]);
}).toThrow();
});
});
describe("tile error handling", function () {
const image = document.createElement("img");
image.src = "images/blank.png";
let terria;
let catalogItem;
let imageryProvider;
let globeOrMap;
let imagery;
let imageryLayer;
beforeEach(function () {
terria = {
error: new CesiumEvent()
};
catalogItem = {
terria: terria,
tileErrorThresholdBeforeDisabling: 5
};
imageryProvider = {
requestImage: function (_x, _y, _level) {
return ImageryProvider.loadImage(this, "images/blank.png");
},
errorEvent: new CesiumEvent()
};
globeOrMap = {
terria: terria,
addImageryProvider: function (options) {
options.imageryProvider.errorEvent.addEventListener(
options.onLoadError
);
return new ImageryLayer(options.imageryProvider);
},
isImageryLayerShown: function () {
return true;
}
};
imagery = {
level: 0,
x: 0,
y: 0
};
terria.currentViewer = globeOrMap;
imageryLayer = ImageryLayerCatalogItem.enableLayer(
catalogItem,
imageryProvider,
1.0,
0,
globeOrMap
);
});
function failLoad(statusCode, times) {
return spyOn(Resource.prototype, "fetchImage").and.callFake(
function (options) {
if (times > 0) {
--times;
if (options.preferBlob) {
return Promise.reject(
new RequestErrorEvent(statusCode, "bad", [])
);
} else {
return Promise.reject(image);
}
} else {
return Promise.resolve(image);
}
}
);
}
it("ignores errors in disabled layers", async function () {
spyOn(globeOrMap, "isImageryLayerShown").and.returnValue(false);
const fetchImage = failLoad(503, 10);
imageryLayer._requestImagery(imagery);
await pollToPromise(function () {
return imagery.state === ImageryState.FAILED;
});
expect(fetchImage.calls.count()).toEqual(1);
});
it("retries images that fail with a 503 error", async function () {
const fetchImage = failLoad(503, 2);
imageryLayer._requestImagery(imagery);
await pollToPromise(function () {
return imagery.state === ImageryState.RECEIVED;
});
expect(fetchImage.calls.count()).toEqual(4);
});
it("eventually gives up on a tile that only succeeds when loaded via blob", async function () {
const fetchImage = spyOn(Resource.prototype, "fetchImage").and.callFake(
function (options) {
if (options.preferBlob) {
return runLater(function () {
return image;
});
} else {
return runLater(function () {
return Promise.reject(image);
});
}
}
);
imageryLayer._requestImagery(imagery);
await pollToPromise(function () {
return imagery.state === ImageryState.FAILED;
});
expect(fetchImage.calls.count()).toBeGreaterThan(5);
});
it("ignores any number of 404 errors if treat404AsError is false", async function () {
const fetchImage = failLoad(404, 100);
catalogItem.treat404AsError = false;
const tiles = [];
for (let i = 0; i < 20; ++i) {
tiles[i] = {
level: 20,
x: i,
y: i
};
imageryLayer._requestImagery(tiles[i]);
}
await pollToPromise(function () {
let result = true;
for (let i = 0; i < tiles.length; ++i) {
result = result && tiles[i].state === ImageryState.FAILED;
}
return result;
});
expect(fetchImage.calls.count()).toEqual(tiles.length * 2);
});
it("ignores any number of 403 errors if treat403AsError is false", async function () {
const fetchImage = failLoad(403, 100);
catalogItem.treat403AsError = false;
const tiles = [];
for (let i = 0; i < 20; ++i) {
tiles[i] = {
level: 20,
x: i,
y: i
};
imageryLayer._requestImagery(tiles[i]);
}
await pollToPromise(function () {
let result = true;
for (let i = 0; i < tiles.length; ++i) {
result = result && tiles[i].state === ImageryState.FAILED;
}
return result;
});
expect(fetchImage.calls.count()).toEqual(tiles.length * 2);
});
it("doesn't disable the layer after only five 404s if treat404AsError is true", async function () {
const fetchImage = failLoad(404, 100);
catalogItem.treat404AsError = true;
catalogItem.isShown = true;
const tiles = [];
for (let i = 0; i < 5; ++i) {
tiles[i] = {
level: 20,
x: i,
y: i
};
imageryLayer._requestImagery(tiles[i]);
}
await pollToPromise(function () {
let result = true;
for (let i = 0; i < tiles.length; ++i) {
result = result && tiles[i].state === ImageryState.FAILED;
}
return result;
});
expect(fetchImage.calls.count()).toEqual(tiles.length * 2);
expect(catalogItem.isShown).toBe(true);
});
it("disables the layer after six 404s if treat404AsError is true", async function () {
const fetchImage = failLoad(404, 100);
catalogItem.treat404AsError = true;
catalogItem.isShown = true;
const tiles = [];
for (let i = 0; i < 6; ++i) {
tiles[i] = {
level: 20,
x: i,
y: i
};
imageryLayer._requestImagery(tiles[i]);
}
await pollToPromise(function () {
let result = true;
for (let i = 0; i < tiles.length; ++i) {
result = result && tiles[i].state === ImageryState.FAILED;
}
return result;
});
expect(fetchImage.calls.count()).toEqual(tiles.length * 2);
expect(catalogItem.isShown).toBe(false);
});
});
});