11import * as http from "http"
2+ import { logger } from "@coder/logger"
3+ import { AddressInfo } from "net"
24import * as path from "path"
35import { SettingsProvider , UpdateSettings } from "../../../src/node/settings"
46import { LatestResponse , UpdateProvider } from "../../../src/node/update"
5- import { clean , mockLogger , tmpdir } from "../../utils/helpers"
7+ import { clean , isAddressInfo , mockLogger , tmpdir } from "../../utils/helpers"
68
79describe ( "update" , ( ) => {
810 let version = "1.0.0"
@@ -23,6 +25,46 @@ describe("update", () => {
2325 return response . end ( JSON . stringify ( latest ) )
2426 }
2527
28+ if ( request . url === "/reject-status-code" ) {
29+ response . writeHead ( 500 )
30+ return response . end ( "rejected status code test" )
31+ }
32+
33+ if ( request . url === "/no-location-header" ) {
34+ response . writeHead ( 301 , "testing" , {
35+ location : "" ,
36+ } )
37+ return response . end ( "rejected status code test" )
38+ }
39+
40+ if ( request . url === "/with-location-header" ) {
41+ response . writeHead ( 301 , "testing" , {
42+ location : "/latest" ,
43+ } )
44+
45+ return response . end ( )
46+ }
47+
48+ // Checks if url matches /redirect/${number}
49+ // with optional trailing slash
50+ const match = request . url . match ( / \/ r e d i r e c t \/ ( [ 0 - 9 ] + ) \/ ? $ / )
51+ if ( match ) {
52+ if ( request . url === "/redirect/0" ) {
53+ response . writeHead ( 200 )
54+ return response . end ( "done" )
55+ }
56+
57+ // Subtract 1 from the current redirect number
58+ // i.e. /redirect/10 -> /redirect/9 -> /redirect/8
59+ const currentRedirectNumber = parseInt ( match [ 1 ] )
60+ const newRedirectNumber = currentRedirectNumber - 1
61+
62+ response . writeHead ( 302 , "testing" , {
63+ location : `/redirect/${ String ( newRedirectNumber ) } ` ,
64+ } )
65+ return response . end ( "" )
66+ }
67+
2668 // Anything else is a 404.
2769 response . writeHead ( 404 )
2870 response . end ( "not found" )
@@ -37,6 +79,7 @@ describe("update", () => {
3779 }
3880
3981 let _provider : UpdateProvider | undefined
82+ let _address : string | AddressInfo | null
4083 const provider = ( ) : UpdateProvider => {
4184 if ( ! _provider ) {
4285 throw new Error ( "Update provider has not been created" )
@@ -62,19 +105,20 @@ describe("update", () => {
62105 } )
63106 } )
64107
65- const address = server . address ( )
66- if ( ! address || typeof address === "string" || ! address . port ) {
108+ _address = server . address ( )
109+ if ( ! isAddressInfo ( _address ) ) {
67110 throw new Error ( "unexpected address" )
68111 }
69112
70- _provider = new UpdateProvider ( `http://${ address . address } :${ address . port } /latest` , _settings )
113+ _provider = new UpdateProvider ( `http://${ _address ? .address } :${ _address ? .port } /latest` , _settings )
71114 } )
72115
73116 afterAll ( ( ) => {
74117 server . close ( )
75118 } )
76119
77120 beforeEach ( ( ) => {
121+ jest . clearAllMocks ( )
78122 spy = [ ]
79123 } )
80124
@@ -170,4 +214,61 @@ describe("update", () => {
170214 expect ( update . checked < Date . now ( ) && update . checked >= now ) . toEqual ( true )
171215 expect ( update . version ) . toStrictEqual ( "unknown" )
172216 } )
217+
218+ it ( "should reject if response has status code 500" , async ( ) => {
219+ if ( isAddressInfo ( _address ) ) {
220+ const mockURL = `http://${ _address . address } :${ _address . port } /reject-status-code`
221+ let provider = new UpdateProvider ( mockURL , settings ( ) )
222+ let update = await provider . getUpdate ( true )
223+
224+ expect ( update . version ) . toBe ( "unknown" )
225+ expect ( logger . error ) . toHaveBeenCalled ( )
226+ expect ( logger . error ) . toHaveBeenCalledWith ( "Failed to get latest version" , {
227+ identifier : "error" ,
228+ value : `${ mockURL } : 500` ,
229+ } )
230+ }
231+ } )
232+
233+ it ( "should reject if no location header provided" , async ( ) => {
234+ if ( isAddressInfo ( _address ) ) {
235+ const mockURL = `http://${ _address . address } :${ _address . port } /no-location-header`
236+ let provider = new UpdateProvider ( mockURL , settings ( ) )
237+ let update = await provider . getUpdate ( true )
238+
239+ expect ( update . version ) . toBe ( "unknown" )
240+ expect ( logger . error ) . toHaveBeenCalled ( )
241+ expect ( logger . error ) . toHaveBeenCalledWith ( "Failed to get latest version" , {
242+ identifier : "error" ,
243+ value : `received redirect with no location header` ,
244+ } )
245+ }
246+ } )
247+
248+ it ( "should resolve the request with response.headers.location" , async ( ) => {
249+ version = "4.1.1"
250+ if ( isAddressInfo ( _address ) ) {
251+ const mockURL = `http://${ _address . address } :${ _address . port } /with-location-header`
252+ let provider = new UpdateProvider ( mockURL , settings ( ) )
253+ let update = await provider . getUpdate ( true )
254+
255+ expect ( logger . error ) . not . toHaveBeenCalled ( )
256+ expect ( update . version ) . toBe ( "4.1.1" )
257+ }
258+ } )
259+
260+ it ( "should reject if more than 10 redirects" , async ( ) => {
261+ if ( isAddressInfo ( _address ) ) {
262+ const mockURL = `http://${ _address . address } :${ _address . port } /redirect/11`
263+ let provider = new UpdateProvider ( mockURL , settings ( ) )
264+ let update = await provider . getUpdate ( true )
265+
266+ expect ( update . version ) . toBe ( "unknown" )
267+ expect ( logger . error ) . toHaveBeenCalled ( )
268+ expect ( logger . error ) . toHaveBeenCalledWith ( "Failed to get latest version" , {
269+ identifier : "error" ,
270+ value : `reached max redirects` ,
271+ } )
272+ }
273+ } )
173274} )
0 commit comments