22 * Tests for API Proxy Server functions
33 */
44
5+ const { deriveCopilotApiTarget } = require ( './server' ) ;
6+
57describe ( 'deriveCopilotApiTarget' , ( ) => {
68 let originalEnv ;
79
@@ -15,166 +17,79 @@ describe('deriveCopilotApiTarget', () => {
1517 process . env = originalEnv ;
1618 } ) ;
1719
18- // Helper function to reload the module and get the derived target
19- function getDerivedTarget ( env = { } ) {
20- // Set environment variables
21- Object . keys ( env ) . forEach ( key => {
22- process . env [ key ] = env [ key ] ;
23- } ) ;
24-
25- // Clear module cache to force re-evaluation
26- delete require . cache [ require . resolve ( './server.js' ) ] ;
27-
28- // Mock the required modules that have side effects
29- jest . mock ( 'http' , ( ) => ( {
30- createServer : jest . fn ( ( ) => ( {
31- listen : jest . fn ( ) ,
32- } ) ) ,
33- } ) ) ;
34-
35- jest . mock ( 'https' , ( ) => ( {
36- request : jest . fn ( ) ,
37- } ) ) ;
38-
39- jest . mock ( './logging' , ( ) => ( {
40- generateRequestId : jest . fn ( ( ) => 'test-id' ) ,
41- sanitizeForLog : jest . fn ( x => x ) ,
42- logRequest : jest . fn ( ) ,
43- } ) ) ;
44-
45- jest . mock ( './metrics' , ( ) => ( {
46- increment : jest . fn ( ) ,
47- gaugeInc : jest . fn ( ) ,
48- gaugeDec : jest . fn ( ) ,
49- observe : jest . fn ( ) ,
50- statusClass : jest . fn ( ( ) => '2xx' ) ,
51- getSummary : jest . fn ( ( ) => ( { } ) ) ,
52- getMetrics : jest . fn ( ( ) => ( { } ) ) ,
53- } ) ) ;
54-
55- jest . mock ( './rate-limiter' , ( ) => ( {
56- create : jest . fn ( ( ) => ( {
57- check : jest . fn ( ( ) => ( { allowed : true } ) ) ,
58- getAllStatus : jest . fn ( ( ) => ( { } ) ) ,
59- } ) ) ,
60- } ) ) ;
61-
62- // We can't easily extract the function since it's not exported,
63- // but we can test via the startup logs which log COPILOT_API_TARGET
64- // For now, let's create a standalone version to test
65- return deriveCopilotApiTargetStandalone ( env ) ;
66- }
67-
68- // Standalone version of the function for testing
69- function deriveCopilotApiTargetStandalone ( env ) {
70- const COPILOT_API_TARGET = env . COPILOT_API_TARGET ;
71- const GITHUB_SERVER_URL = env . GITHUB_SERVER_URL ;
72-
73- if ( COPILOT_API_TARGET ) {
74- return COPILOT_API_TARGET ;
75- }
76-
77- if ( GITHUB_SERVER_URL ) {
78- try {
79- const hostname = new URL ( GITHUB_SERVER_URL ) . hostname ;
80- if ( hostname !== 'github.com' ) {
81- // For GitHub Enterprise Cloud with data residency (*.ghe.com),
82- // derive the API endpoint as api.SUBDOMAIN.ghe.com
83- if ( hostname . endsWith ( '.ghe.com' ) ) {
84- const subdomain = hostname . replace ( '.ghe.com' , '' ) ;
85- return `api.${ subdomain } .ghe.com` ;
86- }
87- // For other enterprise hosts (GHES), use the generic enterprise endpoint
88- return 'api.enterprise.githubcopilot.com' ;
89- }
90- } catch {
91- // Invalid URL — fall through to default
92- }
93- }
94- return 'api.githubcopilot.com' ;
95- }
96-
9720 test ( 'should return default api.githubcopilot.com when no env vars set' , ( ) => {
98- const target = getDerivedTarget ( { } ) ;
21+ delete process . env . COPILOT_API_TARGET ;
22+ delete process . env . GITHUB_SERVER_URL ;
23+
24+ const target = deriveCopilotApiTarget ( ) ;
9925 expect ( target ) . toBe ( 'api.githubcopilot.com' ) ;
10026 } ) ;
10127
10228 test ( 'should use COPILOT_API_TARGET when explicitly set' , ( ) => {
103- const target = getDerivedTarget ( {
104- COPILOT_API_TARGET : 'custom.api.example.com' ,
105- } ) ;
29+ process . env . COPILOT_API_TARGET = 'custom.api.example.com' ;
30+ const target = deriveCopilotApiTarget ( ) ;
10631 expect ( target ) . toBe ( 'custom.api.example.com' ) ;
10732 } ) ;
10833
10934 test ( 'should prioritize COPILOT_API_TARGET over GITHUB_SERVER_URL' , ( ) => {
110- const target = getDerivedTarget ( {
111- COPILOT_API_TARGET : 'custom.api.example.com' ,
112- GITHUB_SERVER_URL : 'https://mycompany.ghe.com' ,
113- } ) ;
35+ process . env . COPILOT_API_TARGET = 'custom.api.example.com' ;
36+ process . env . GITHUB_SERVER_URL = 'https://mycompany.ghe.com' ;
37+ const target = deriveCopilotApiTarget ( ) ;
11438 expect ( target ) . toBe ( 'custom.api.example.com' ) ;
11539 } ) ;
11640
11741 test ( 'should return api.githubcopilot.com for github.com' , ( ) => {
118- const target = getDerivedTarget ( {
119- GITHUB_SERVER_URL : 'https://github.com' ,
120- } ) ;
42+ process . env . GITHUB_SERVER_URL = 'https://github.com' ;
43+ const target = deriveCopilotApiTarget ( ) ;
12144 expect ( target ) . toBe ( 'api.githubcopilot.com' ) ;
12245 } ) ;
12346
12447 test ( 'should derive api.SUBDOMAIN.ghe.com for *.ghe.com domains' , ( ) => {
125- const target = getDerivedTarget ( {
126- GITHUB_SERVER_URL : 'https://mycompany.ghe.com' ,
127- } ) ;
48+ process . env . GITHUB_SERVER_URL = 'https://mycompany.ghe.com' ;
49+ const target = deriveCopilotApiTarget ( ) ;
12850 expect ( target ) . toBe ( 'api.mycompany.ghe.com' ) ;
12951 } ) ;
13052
13153 test ( 'should derive api.SUBDOMAIN.ghe.com for different *.ghe.com subdomain' , ( ) => {
132- const target = getDerivedTarget ( {
133- GITHUB_SERVER_URL : 'https://acme-corp.ghe.com' ,
134- } ) ;
54+ process . env . GITHUB_SERVER_URL = 'https://acme-corp.ghe.com' ;
55+ const target = deriveCopilotApiTarget ( ) ;
13556 expect ( target ) . toBe ( 'api.acme-corp.ghe.com' ) ;
13657 } ) ;
13758
13859 test ( 'should use api.enterprise.githubcopilot.com for GHES (non-.ghe.com enterprise)' , ( ) => {
139- const target = getDerivedTarget ( {
140- GITHUB_SERVER_URL : 'https://github.enterprise.com' ,
141- } ) ;
60+ process . env . GITHUB_SERVER_URL = 'https://github.enterprise.com' ;
61+ const target = deriveCopilotApiTarget ( ) ;
14262 expect ( target ) . toBe ( 'api.enterprise.githubcopilot.com' ) ;
14363 } ) ;
14464
14565 test ( 'should use api.enterprise.githubcopilot.com for custom GHES domain' , ( ) => {
146- const target = getDerivedTarget ( {
147- GITHUB_SERVER_URL : 'https://git.mycompany.com' ,
148- } ) ;
66+ process . env . GITHUB_SERVER_URL = 'https://git.mycompany.com' ;
67+ const target = deriveCopilotApiTarget ( ) ;
14968 expect ( target ) . toBe ( 'api.enterprise.githubcopilot.com' ) ;
15069 } ) ;
15170
15271 test ( 'should handle GITHUB_SERVER_URL without protocol gracefully' , ( ) => {
153- const target = getDerivedTarget ( {
154- GITHUB_SERVER_URL : 'mycompany.ghe.com' ,
155- } ) ;
72+ process . env . GITHUB_SERVER_URL = 'mycompany.ghe.com' ;
73+ const target = deriveCopilotApiTarget ( ) ;
15674 // Invalid URL, should fall back to default
15775 expect ( target ) . toBe ( 'api.githubcopilot.com' ) ;
15876 } ) ;
15977
16078 test ( 'should handle invalid GITHUB_SERVER_URL gracefully' , ( ) => {
161- const target = getDerivedTarget ( {
162- GITHUB_SERVER_URL : 'not-a-valid-url' ,
163- } ) ;
79+ process . env . GITHUB_SERVER_URL = 'not-a-valid-url' ;
80+ const target = deriveCopilotApiTarget ( ) ;
16481 expect ( target ) . toBe ( 'api.githubcopilot.com' ) ;
16582 } ) ;
16683
16784 test ( 'should handle GITHUB_SERVER_URL with port' , ( ) => {
168- const target = getDerivedTarget ( {
169- GITHUB_SERVER_URL : 'https://mycompany.ghe.com:443' ,
170- } ) ;
85+ process . env . GITHUB_SERVER_URL = 'https://mycompany.ghe.com:443' ;
86+ const target = deriveCopilotApiTarget ( ) ;
17187 expect ( target ) . toBe ( 'api.mycompany.ghe.com' ) ;
17288 } ) ;
17389
17490 test ( 'should handle GITHUB_SERVER_URL with path' , ( ) => {
175- const target = getDerivedTarget ( {
176- GITHUB_SERVER_URL : 'https://mycompany.ghe.com/some/path' ,
177- } ) ;
91+ process . env . GITHUB_SERVER_URL = 'https://mycompany.ghe.com/some/path' ;
92+ const target = deriveCopilotApiTarget ( ) ;
17893 expect ( target ) . toBe ( 'api.mycompany.ghe.com' ) ;
17994 } ) ;
18095} ) ;
0 commit comments