Skip to content

Commit

Permalink
test: fetch retry (#162)
Browse files Browse the repository at this point in the history
This PR adds retry to the fetch requests. It also fixes the tests that were having issues when running locally.
  • Loading branch information
joacoc authored Dec 7, 2023
1 parent 3765dee commit e1958c1
Show file tree
Hide file tree
Showing 11 changed files with 62 additions and 31 deletions.
6 changes: 3 additions & 3 deletions src/clients/admin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import fetch from "node-fetch";
import AppPassword from "../context/appPassword";
import { Errors, ExtensionError } from "../utilities/error";
import jwksClient from "jwks-rsa";
import { verify } from "node-jsonwebtoken";
import { fetchWithRetry } from "../utilities/utils";

interface AuthenticationResponse {
accessToken: string,
Expand Down Expand Up @@ -44,11 +44,11 @@ export default class AdminClient {
secret: this.appPassword.secretKey
};

const response = await fetch(this.adminEndpoint, {
const response = await fetchWithRetry(this.adminEndpoint, {
method: 'post',
body: JSON.stringify(authRequest),
// eslint-disable-next-line @typescript-eslint/naming-convention
headers: {'Content-Type': 'application/json'}
headers: {'Content-Type': 'application/json' }
});

if (response.status === 200) {
Expand Down
4 changes: 2 additions & 2 deletions src/clients/cloud.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fetch from "node-fetch";
import AdminClient from "./admin";
import { Errors, ExtensionError } from "../utilities/error";
import { fetchWithRetry } from "../utilities/utils";

const DEFAULT_API_CLOUD_ENDPOINT = 'https://api.cloud.materialize.com';

Expand Down Expand Up @@ -58,7 +58,7 @@ export default class CloudClient {
}

async fetch(endpoint: string) {
return fetch(endpoint, {
return fetchWithRetry(endpoint, {
method: 'get',
headers: {
// eslint-disable-next-line @typescript-eslint/naming-convention
Expand Down
8 changes: 4 additions & 4 deletions src/clients/lsp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
import fetch from "node-fetch";
import path from "path";
import * as vscode from "vscode";
import {
Expand All @@ -16,6 +15,7 @@ import os from "os";
import { SemVer } from "semver";
import { Errors, ExtensionError } from "../utilities/error";
import * as Sentry from "@sentry/node";
import { fetchWithRetry } from "../utilities/utils";

// This endpoint returns a string with the latest LSP version.
const BINARIES_ENDPOINT = "https://binaries.materialize.com";
Expand Down Expand Up @@ -144,7 +144,7 @@ export default class LspClient {
bufferStream
.pipe(gunzip)
.pipe(extract)
.on('finish', (d: any) => {
.on('finish', () => {
console.log("[LSP]", "Server installed.");
res("");
})
Expand Down Expand Up @@ -198,7 +198,7 @@ export default class LspClient {
*/
private async fetchLatestVersionNumber() {
console.log("[LSP]", "Fetching latest version number.");
const response = await fetch(LATEST_VERSION_ENDPOINT);
const response = await fetchWithRetry(LATEST_VERSION_ENDPOINT);
const latestVersion: string = await response.text();

return new SemVer(latestVersion);
Expand All @@ -213,7 +213,7 @@ export default class LspClient {
const endpoint = this.getEndpointByOs(latestVersion);

console.log("[LSP]", `Fetching LSP from: ${endpoint}`);
const binaryResponse = await fetch(endpoint);
const binaryResponse = await fetchWithRetry(endpoint);
const buffer = await binaryResponse.arrayBuffer();

return buffer;
Expand Down
3 changes: 1 addition & 2 deletions src/providers/auth.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as vscode from "vscode";
import express, { Request, Response, Application, } from 'express';
import { getUri } from "../utilities/getUri";
import { getNonce, getUri } from "../utilities/utils";
import AppPassword from "../context/appPassword";
import { getNonce } from "../utilities/getNonce";
import AsyncContext from "../context/asyncContext";
import { Errors, ExtensionError } from "../utilities/error";

Expand Down
3 changes: 1 addition & 2 deletions src/providers/results.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as vscode from "vscode";
import { getUri } from "../utilities/getUri";
import { getNonce } from "../utilities/getNonce";
import { getNonce, getUri } from "../utilities/utils";
import { QueryResult } from "pg";

interface Results extends QueryResult {
Expand Down
5 changes: 3 additions & 2 deletions src/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,13 +255,14 @@ suite('Extension Test Suite', () => {
let err = false;
try {
await context.setProfile("invalid_profile");
} catch (error) {
} catch (error: any) {
assert.ok(error.message === "Invalid authentication");
err = true;
}

assert.ok(err);

}).timeout(10000);
}).timeout(30000);

test('Alternative parser', async () => {
const lsp = new LspClient();
Expand Down
4 changes: 2 additions & 2 deletions src/test/suite/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ export function mockServer(): Promise<string> {
});

return new Promise((res) => {
app.listen(3000, 'localhost', () => {
console.log(`Mock server listening at localhost:3000`);
const server = app.listen(3000, 'localhost', () => {
console.log(`Mock server listening at localhost:3000: `, server.listening);
res("Loaded.");
});
});
Expand Down
6 changes: 5 additions & 1 deletion src/utilities/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,9 @@ export enum Errors {
/**
* Raises when it is impossible to parse the statements.
*/
parsingFailure = " Error parsing the statements.",
parsingFailure = "Error parsing the statements.",
/**
* Raises when a fetch failes after a minute.
*/
fetchTimeoutError = "Failed to fetch after a minute."
}
8 changes: 0 additions & 8 deletions src/utilities/getNonce.ts

This file was deleted.

5 changes: 0 additions & 5 deletions src/utilities/getUri.ts

This file was deleted.

41 changes: 41 additions & 0 deletions src/utilities/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Uri, Webview } from "vscode";
import { Errors, ExtensionError } from "./error";

export function getNonce() {
let text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}

export function getUri(webview: Webview, extensionUri: Uri, pathList: string[]) {
return webview.asWebviewUri(Uri.joinPath(extensionUri, ...pathList));
}

export async function fetchWithRetry(
url: string,
init?: RequestInit,
timeout = 60000,
interval = 5000
): Promise<Response> {
const startTime = Date.now();

async function attemptFetch(): Promise<Response> {
try {
const response = await fetch(url, init);
return response;
} catch (error) {
console.error("[Fetch]", "Error fetching: ", error);
if (Date.now() - startTime < timeout) {
await new Promise(resolve => setTimeout(resolve, interval));
return attemptFetch();
} else {
throw new ExtensionError(Errors.fetchTimeoutError, `Failed to fetch after ${timeout}ms: ${error}`);
}
}
}

return attemptFetch();
}

0 comments on commit e1958c1

Please sign in to comment.