UMassCDS / satellite-imagery-labeling-tool

This is a lightweight web-interface for creating and sharing vector annotations over satellite/aerial imagery scenes.
MIT License
2 stars 1 forks source link

Add front end tests for memory leaks #16

Open tnmygrwl opened 1 year ago

tnmygrwl commented 1 year ago

As a developer, I would like to have tests for the satellite imagery labeling tool to check for memory leaks and that the cache is appropriately cleared, so that I can verify that the tool does not have memory leaks and that new code changes do not introduce any.

Steps

  1. Test for Memory Leaks: We need to monitor the memory usage of our application over time, especially when interacting with discount.js and labeler.js. Tools like Chrome's Memory Profiler can be used to identify potential memory leaks.

  2. Test Cache Release: When the labeler.js page is reloaded, it offers to resume from the last spot. We need to ensure that this feature doesn't cause memory leaks. We should test that old cache data is appropriately released when a new session is started.

  3. Test Map Loading Speed: We need to ensure that maps load quickly when tiles are loaded. We should measure the time it takes to load tiles and aim to minimize this time.

The following code snippets are relevant to this ticket:

/** The main logic for the spatial annotation labeler app. */
export class LabelerApp {
    ...
    /**
     * Saves all drawn data in local storage for the project.
     */
    #saveSession = async () => {
        //Get clean source data.
        const self = this;
        if (appSettings.autoSave.enabled) {
            const json = self.#getSourceData(false, true);

            //Store a copy of the data, date, and the name of the project.
            await self.#storage.setItem(self.config.properties.name, {
                data: json,
                date: Date.now()
            });
        }

        self.#calcStats();
    }

    /**
     * Calculate stats on the drawn features.
     */
    #calcStats = () => {
        if (this.#statsControl) {
            const statsInfo = [];

            const fc = this.#featureSource.toJson();

            statsInfo.push(`Number of shapes: ${fc.features.length}`)

            let c1 = 0;
            let c2 = 0;

            fc.features.forEach(f => {

            });

            this.#statsControl.setOptions({
                content: statsInfo.join(''),
                visible: true
            });
        }
    }

    /**
     * Checks to see if any data for the project exists in local storage. If it does, asks if the user would like to recover it.
     */
    async #checkStorage() {
        const self = this;

        //If auto save is disabled, don't try and load any data.
        if (appSettings.autoSave.enabled) {
            const today = new Date();

            //Calcuate the expiry date for old cached data.
            const expiryDate = new Date().setDate(today.getDate() - appSettings.autoSave.ttl);

            await self.#storage.iterate((value, key) => {
                //Check to see if there is cached data for the named project.
                if (key === self.config.properties.name) {
                    //Check to see if the user wants to recover it.
                    if (value && confirm('Found cached data for this project task. Continue from where you left off?')) {
                        self.#featureSource.setShapes(value.data);
                        self.#calcStats();
                    } else {
                        //If not, clear the cached data.
                        self.#removeExpireData(key).then();
                    }
                } else if (value.date < expiryDate) {
                    //Check other cached data to see if it's older than the expiry date. If so, remove it.
                    self.#removeExpireData(key).then();
                }
            });
        }
    }
/** The main logic for the spatial annotation labeler app. */
export class LabelerApp {
    ...
    ///////////////////////////
    // Constructor
    //////////////////////////

    /** The main logic for the spatial annotation labeler app. */
    constructor() {
        ...
        self.flyout.on('closed', (item) => {
            self.navbar.setSelectedItem('');
            self.navbar.focus();
        });

        //Initialize a map instance.
        self.map = Utils.createMap('myMap', mapSettings.azureMapsAuth);

        self.map.events.add('ready', self.#mapReady);

        //Make clone of the default config.
        self.config = Object.assign({}, appSettings.defaultConfig.features[0]);

        //Check to see if the URL contains a URL path.
        const queryString = window.location.search;
        const urlParams = new URLSearchParams(queryString);

        if (urlParams.has("taskUrl")) {
            let taskUrl = urlParams.get('taskUrl');

            if (taskUrl && taskUrl !== '') {
                if (taskUrl.indexOf('%2F') > -1) {
                    //Assume URL is encoded, decode it.
                    taskUrl = decodeURIComponent(taskUrl);
                }

                fetch(taskUrl).then(x => {
                    return x.json();
                }).then(fc => {
                    if (fc.features && fc.features.length > 0) {
                        self.config = fc.features[0];
                    }
                    self.#loadConfig();
                });
            }
        } else {
            self.#loadConfig();
        }

        document.getElementById('app-theme').onchange = self.#themeColorChanged;

        //Initialized the flyout panels.
        self.#initLoadPanel();
        self.#initLayerPanel();
        self.#initSavePanel();
        self.#initScreenshotPanel();
        self.#initPowerTools();

Acceptance Criteria

Definition of Done:

Time Box:

5 days to complete it, including writing tests, running them, and fixing any identified issues.