feat: add tests for update.ts (#4835)
* feat: add isAddressInfo helper function * feat(update): add test for rejection UpdateProvider * feat: add more tests for UpdateProvider * fixup! move isAddressInfo, add .address check * fixup! remove extra writeHead * fixup! use -1 in redirect logic * fixup! remove unnecessary String call * fixup! use /latest for redirect * fixup! use match group for regex * fixup!: replace match/split logic
This commit is contained in:
parent
102478bdea
commit
c9c5c54cda
@ -1,8 +1,10 @@
|
|||||||
import * as http from "http"
|
import * as http from "http"
|
||||||
|
import { logger } from "@coder/logger"
|
||||||
|
import { AddressInfo } from "net"
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import { SettingsProvider, UpdateSettings } from "../../../src/node/settings"
|
import { SettingsProvider, UpdateSettings } from "../../../src/node/settings"
|
||||||
import { LatestResponse, UpdateProvider } from "../../../src/node/update"
|
import { LatestResponse, UpdateProvider } from "../../../src/node/update"
|
||||||
import { clean, mockLogger, tmpdir } from "../../utils/helpers"
|
import { clean, isAddressInfo, mockLogger, tmpdir } from "../../utils/helpers"
|
||||||
|
|
||||||
describe("update", () => {
|
describe("update", () => {
|
||||||
let version = "1.0.0"
|
let version = "1.0.0"
|
||||||
@ -23,6 +25,46 @@ describe("update", () => {
|
|||||||
return response.end(JSON.stringify(latest))
|
return response.end(JSON.stringify(latest))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.url === "/reject-status-code") {
|
||||||
|
response.writeHead(500)
|
||||||
|
return response.end("rejected status code test")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.url === "/no-location-header") {
|
||||||
|
response.writeHead(301, "testing", {
|
||||||
|
location: "",
|
||||||
|
})
|
||||||
|
return response.end("rejected status code test")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.url === "/with-location-header") {
|
||||||
|
response.writeHead(301, "testing", {
|
||||||
|
location: "/latest",
|
||||||
|
})
|
||||||
|
|
||||||
|
return response.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if url matches /redirect/${number}
|
||||||
|
// with optional trailing slash
|
||||||
|
const match = request.url.match(/\/redirect\/([0-9]+)\/?$/)
|
||||||
|
if (match) {
|
||||||
|
if (request.url === "/redirect/0") {
|
||||||
|
response.writeHead(200)
|
||||||
|
return response.end("done")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract 1 from the current redirect number
|
||||||
|
// i.e. /redirect/10 -> /redirect/9 -> /redirect/8
|
||||||
|
const currentRedirectNumber = parseInt(match[1])
|
||||||
|
const newRedirectNumber = currentRedirectNumber - 1
|
||||||
|
|
||||||
|
response.writeHead(302, "testing", {
|
||||||
|
location: `/redirect/${String(newRedirectNumber)}`,
|
||||||
|
})
|
||||||
|
return response.end("")
|
||||||
|
}
|
||||||
|
|
||||||
// Anything else is a 404.
|
// Anything else is a 404.
|
||||||
response.writeHead(404)
|
response.writeHead(404)
|
||||||
response.end("not found")
|
response.end("not found")
|
||||||
@ -37,6 +79,7 @@ describe("update", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let _provider: UpdateProvider | undefined
|
let _provider: UpdateProvider | undefined
|
||||||
|
let _address: string | AddressInfo | null
|
||||||
const provider = (): UpdateProvider => {
|
const provider = (): UpdateProvider => {
|
||||||
if (!_provider) {
|
if (!_provider) {
|
||||||
throw new Error("Update provider has not been created")
|
throw new Error("Update provider has not been created")
|
||||||
@ -62,12 +105,12 @@ describe("update", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const address = server.address()
|
_address = server.address()
|
||||||
if (!address || typeof address === "string" || !address.port) {
|
if (!isAddressInfo(_address)) {
|
||||||
throw new Error("unexpected address")
|
throw new Error("unexpected address")
|
||||||
}
|
}
|
||||||
|
|
||||||
_provider = new UpdateProvider(`http://${address.address}:${address.port}/latest`, _settings)
|
_provider = new UpdateProvider(`http://${_address?.address}:${_address?.port}/latest`, _settings)
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
@ -75,6 +118,7 @@ describe("update", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks()
|
||||||
spy = []
|
spy = []
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -170,4 +214,61 @@ describe("update", () => {
|
|||||||
expect(update.checked < Date.now() && update.checked >= now).toEqual(true)
|
expect(update.checked < Date.now() && update.checked >= now).toEqual(true)
|
||||||
expect(update.version).toStrictEqual("unknown")
|
expect(update.version).toStrictEqual("unknown")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should reject if response has status code 500", async () => {
|
||||||
|
if (isAddressInfo(_address)) {
|
||||||
|
const mockURL = `http://${_address.address}:${_address.port}/reject-status-code`
|
||||||
|
let provider = new UpdateProvider(mockURL, settings())
|
||||||
|
let update = await provider.getUpdate(true)
|
||||||
|
|
||||||
|
expect(update.version).toBe("unknown")
|
||||||
|
expect(logger.error).toHaveBeenCalled()
|
||||||
|
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||||
|
identifier: "error",
|
||||||
|
value: `${mockURL}: 500`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should reject if no location header provided", async () => {
|
||||||
|
if (isAddressInfo(_address)) {
|
||||||
|
const mockURL = `http://${_address.address}:${_address.port}/no-location-header`
|
||||||
|
let provider = new UpdateProvider(mockURL, settings())
|
||||||
|
let update = await provider.getUpdate(true)
|
||||||
|
|
||||||
|
expect(update.version).toBe("unknown")
|
||||||
|
expect(logger.error).toHaveBeenCalled()
|
||||||
|
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||||
|
identifier: "error",
|
||||||
|
value: `received redirect with no location header`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should resolve the request with response.headers.location", async () => {
|
||||||
|
version = "4.1.1"
|
||||||
|
if (isAddressInfo(_address)) {
|
||||||
|
const mockURL = `http://${_address.address}:${_address.port}/with-location-header`
|
||||||
|
let provider = new UpdateProvider(mockURL, settings())
|
||||||
|
let update = await provider.getUpdate(true)
|
||||||
|
|
||||||
|
expect(logger.error).not.toHaveBeenCalled()
|
||||||
|
expect(update.version).toBe("4.1.1")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should reject if more than 10 redirects", async () => {
|
||||||
|
if (isAddressInfo(_address)) {
|
||||||
|
const mockURL = `http://${_address.address}:${_address.port}/redirect/11`
|
||||||
|
let provider = new UpdateProvider(mockURL, settings())
|
||||||
|
let update = await provider.getUpdate(true)
|
||||||
|
|
||||||
|
expect(update.version).toBe("unknown")
|
||||||
|
expect(logger.error).toHaveBeenCalled()
|
||||||
|
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
|
||||||
|
identifier: "error",
|
||||||
|
value: `reached max redirects`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -105,3 +105,17 @@ export function idleTimer(message: string, reject: (error: Error) => void, delay
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper function which returns a boolean indicating whether
|
||||||
|
* the given address is AddressInfo and has .address
|
||||||
|
* and a .port property.
|
||||||
|
*/
|
||||||
|
export function isAddressInfo(address: unknown): address is net.AddressInfo {
|
||||||
|
return (
|
||||||
|
address !== null &&
|
||||||
|
typeof address !== "string" &&
|
||||||
|
(address as net.AddressInfo).port !== undefined &&
|
||||||
|
(address as net.AddressInfo).address !== undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user