139 lines
3.9 KiB
TypeScript
139 lines
3.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { findTailscaleServePort, detectTailscaleServe, hasGwPathHandler } from '@/lib/tailscale-serve'
|
|
|
|
// Realistic Tailscale Serve status JSON matching the structure returned by
|
|
// `tailscale serve status --json`
|
|
const TYPICAL_WEB_CONFIG = {
|
|
'myhost.tailb5729a.ts.net:8443': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://localhost:18789' },
|
|
},
|
|
},
|
|
'myhost.tailb5729a.ts.net:8444': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:3000' },
|
|
},
|
|
},
|
|
'myhost.tailb5729a.ts.net:3001': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:3002' },
|
|
},
|
|
},
|
|
}
|
|
|
|
const GW_PATH_WEB_CONFIG = {
|
|
'myhost.tailb5729a.ts.net:443': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:3000' },
|
|
'/gw': { Proxy: 'http://127.0.0.1:18789' },
|
|
},
|
|
},
|
|
}
|
|
|
|
describe('findTailscaleServePort', () => {
|
|
it('finds the external port proxying to a given local port', () => {
|
|
expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 18789)).toBe(8443)
|
|
expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 3000)).toBe(8444)
|
|
expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 3002)).toBe(3001)
|
|
})
|
|
|
|
it('returns null when no handler matches the target port', () => {
|
|
expect(findTailscaleServePort(TYPICAL_WEB_CONFIG, 9999)).toBeNull()
|
|
})
|
|
|
|
it('returns null for null/undefined web config', () => {
|
|
expect(findTailscaleServePort(null, 18789)).toBeNull()
|
|
expect(findTailscaleServePort(undefined, 18789)).toBeNull()
|
|
})
|
|
|
|
it('returns null for empty web config', () => {
|
|
expect(findTailscaleServePort({}, 18789)).toBeNull()
|
|
})
|
|
|
|
it('handles handlers without Proxy field', () => {
|
|
const web = {
|
|
'myhost.ts.net:443': {
|
|
Handlers: {
|
|
'/': { Path: '/var/www' },
|
|
},
|
|
},
|
|
}
|
|
expect(findTailscaleServePort(web, 3000)).toBeNull()
|
|
})
|
|
|
|
it('matches proxy URLs with trailing slash', () => {
|
|
const web = {
|
|
'myhost.ts.net:9000': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:4000/' },
|
|
},
|
|
},
|
|
}
|
|
expect(findTailscaleServePort(web, 4000)).toBe(9000)
|
|
})
|
|
|
|
it('does not match partial port numbers', () => {
|
|
const web = {
|
|
'myhost.ts.net:443': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:18789' },
|
|
},
|
|
},
|
|
}
|
|
// Port 1878 should not match a proxy to 18789
|
|
expect(findTailscaleServePort(web, 1878)).toBeNull()
|
|
// Port 8789 should not match
|
|
expect(findTailscaleServePort(web, 8789)).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('detectTailscaleServe', () => {
|
|
it('detects /gw path-based proxy', () => {
|
|
expect(detectTailscaleServe(GW_PATH_WEB_CONFIG)).toBe(true)
|
|
})
|
|
|
|
it('detects port-based proxy to gateway default port 18789', () => {
|
|
expect(detectTailscaleServe(TYPICAL_WEB_CONFIG)).toBe(true)
|
|
})
|
|
|
|
it('returns false when no gateway proxy found', () => {
|
|
const web = {
|
|
'myhost.ts.net:3000': {
|
|
Handlers: {
|
|
'/': { Proxy: 'http://127.0.0.1:3000' },
|
|
},
|
|
},
|
|
}
|
|
expect(detectTailscaleServe(web)).toBe(false)
|
|
})
|
|
|
|
it('returns false for null/undefined web config', () => {
|
|
expect(detectTailscaleServe(null)).toBe(false)
|
|
expect(detectTailscaleServe(undefined)).toBe(false)
|
|
})
|
|
|
|
it('returns false for empty web config with no config path', () => {
|
|
expect(detectTailscaleServe({})).toBe(false)
|
|
})
|
|
|
|
it('handles host entries with no Handlers', () => {
|
|
const web = { 'myhost.ts.net:443': {} }
|
|
expect(detectTailscaleServe(web)).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('hasGwPathHandler', () => {
|
|
it('returns true when /gw handler exists', () => {
|
|
expect(hasGwPathHandler(GW_PATH_WEB_CONFIG)).toBe(true)
|
|
})
|
|
|
|
it('returns false when no /gw handler exists', () => {
|
|
expect(hasGwPathHandler(TYPICAL_WEB_CONFIG)).toBe(false)
|
|
})
|
|
|
|
it('returns false for null/undefined', () => {
|
|
expect(hasGwPathHandler(null)).toBe(false)
|
|
expect(hasGwPathHandler(undefined)).toBe(false)
|
|
})
|
|
})
|