Unverified Commit 63bd70b2 authored by Marius van den Beek's avatar Marius van den Beek Committed by GitHub
Browse files

Merge pull request #14233 from mvdbeek/history_poller_robustness

[22.05] Place watchHistory logic in try/catch/finally
parents d4771e8c d63e76c5
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 * submitted, delayed only by the throttle period and the request response time.
 */

import store from "store/index";
import defaultStore from "store/index";
import { urlData } from "utils/url";
import { getCurrentHistoryFromServer } from "./queries";
import { getGalaxyInstance } from "app";
@@ -21,7 +21,7 @@ let lastUpdateTime = null;
// last time changed history items have been requested
let lastRequestDate = new Date();

export async function watchHistory() {
export async function watchHistoryOnce(store) {
    // "Reset" watchTimeout so we don't queue up watchHistory calls in rewatchHistory.
    watchTimeout = null;
    // get current history
@@ -64,10 +64,20 @@ export async function watchHistory() {
            });
        }
    }
}

export async function watchHistory(store = defaultStore) {
    try {
        await watchHistoryOnce(store);
    } catch (error) {
        // would be fantastic if we could show some error alerting the user to this
        console.warn(error);
    } finally {
        watchTimeout = setTimeout(() => {
        watchHistory();
            watchHistory(store);
        }, throttlePeriod);
    }
}

export function rewatchHistory() {
    if (watchTimeout) {
+113 −34
Original line number Diff line number Diff line
import MockAdapter from "axios-mock-adapter";
import axios from "axios";
import { watchHistory } from "./watchHistory";
import store from "store/index";
import { watchHistoryOnce } from "./watchHistory";
import { collectionElementsStore } from "store/historyStore/collectionElementsStore";
import { datasetStore } from "store/historyStore/datasetStore";
import { historyStore } from "store/historyStore/historyStore";
import { historyItemsStore } from "store/historyStore/historyItemsStore";
import { mount, createLocalVue } from "@vue/test-utils";
import Vuex from "vuex";

const testApp = {
    template: `<div/>`,
    computed: {
        currentHistoryId() {
            return this.$store.getters["history/currentHistoryId"];
        },
    },
    methods: {
        getHistoryItems(filterObj) {
            return this.$store.getters["getHistoryItems"](filterObj);
        },
    },
};

describe("watchHistory", () => {
    let axiosMock;

    beforeEach(() => {
        axiosMock = new MockAdapter(axios);
    let wrapper;
    const historyData = {
        id: "history-id",
        update_time: "0",
    };
        axiosMock.onGet(`/history/current_history_json`).reply(200, historyData);
    const historyItems = [
        {
            id: "id-1",
@@ -21,6 +37,7 @@ describe("watchHistory", () => {
            state: "ok",
            deleted: false,
            visible: true,
            history_id: "history-id",
        },
        {
            id: "id-2",
@@ -29,21 +46,83 @@ describe("watchHistory", () => {
            state: "error",
            deleted: false,
            visible: true,
            history_id: "history-id",
        },
    ];
        axiosMock.onGet(/api\/histories\/history-id\/contents?.*/).reply(200, historyItems);

    beforeEach(() => {
        axiosMock = new MockAdapter(axios);
        const localVue = createLocalVue();
        localVue.use(Vuex);

        wrapper = mount(testApp, {
            store: new Vuex.Store({
                modules: {
                    collectionElements: collectionElementsStore,
                    dataset: datasetStore,
                    history: historyStore,
                    historyItems: historyItemsStore,
                },
            }),
            localVue,
        });
    });

    afterEach(() => {
        axiosMock.restore();
        axiosMock.reset();
    });

    it("store initialization", async () => {
        expect(store.getters["history/currentHistoryId"]).toBe(null);
        await watchHistory();
        expect(store.getters["history/currentHistoryId"]).toBe("history-id");
        expect(store.getters["getHistoryItems"]({ historyId: "history-id", filterText: "" }).length).toBe(2);
        expect(store.getters["getHistoryItems"]({ historyId: "history-id", filterText: "second" })[0].hid).toBe(2);
        expect(store.getters["getHistoryItems"]({ historyId: "history-id", filterText: "state:ok" })[0].hid).toBe(1);
    it("sets up the history and history item stores", async () => {
        axiosMock
            .onGet(`/history/current_history_json`)
            .replyOnce(200, historyData)
            .onGet(/api\/histories\/history-id\/contents?.*/)
            .replyOnce(200, historyItems);
        await watchHistoryOnce(wrapper.vm.$store);
        expect(wrapper.vm.getHistoryItems({ historyId: "history-id", filterText: "" }).length).toBe(2);
        expect(wrapper.vm.getHistoryItems({ historyId: "history-id", filterText: "second" })[0].hid).toBe(2);
        expect(wrapper.vm.getHistoryItems({ historyId: "history-id", filterText: "state:ok" })[0].hid).toBe(1);
    });

    it("survives a failing request", async () => {
        // Setup a failing request, then update history content
        axiosMock
            .onGet(`/history/current_history_json`)
            .replyOnce(200, historyData)
            .onGet(/api\/histories\/history-id\/contents?.*/)
            .replyOnce(200, historyItems)
            .onGet(`/history/current_history_json`)
            .replyOnce(500);

        await watchHistoryOnce(wrapper.vm.$store);
        expect(wrapper.vm.currentHistoryId).toBe("history-id");
        expect(wrapper.vm.getHistoryItems({ historyId: "history-id", filterText: "" }).length).toBe(2);
        try {
            await watchHistoryOnce(wrapper.vm.$store);
        } catch (error) {
            console.log(error);
            expect(error.response.status).toBe(500);
        }
        // Need to reset axios mock here. Smells like a bug,
        // maybe in axios-mock-adapter, maybe on our side
        axiosMock.reset();
        axiosMock
            .onGet(`/history/current_history_json`)
            .replyOnce(200, { ...historyData, update_time: "1" })
            .onGet(/api\/histories\/history-id\/contents?.*/)
            .replyOnce(200, [
                {
                    id: "id-3",
                    hid: 3,
                    name: "third",
                    state: "ok",
                    deleted: false,
                    visible: true,
                    history_id: "history-id",
                },
            ]);
        await watchHistoryOnce(wrapper.vm.$store);
        // We should have received the update and have 3 items in the history
        expect(wrapper.vm.getHistoryItems({ historyId: "history-id", filterText: "" }).length).toBe(3);
    });
});