/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ using GitHub.Copilot.Test.Harness; using Xunit; namespace GitHub.Copilot.Test; /// /// Custom fixture that spawns a CLI in TCP mode with an explicit connection token, so /// sibling clients can attempt to connect to the same port with the right/wrong/no token. /// public class ConnectionTokenTestFixture : IAsyncLifetime { public E2ETestContext Ctx { get; private set; } = null!; public CopilotClient GoodClient { get; private set; } = null!; public int Port { get; private set; } public const string Token = "right-token"; public async Task InitializeAsync() { Ctx = await E2ETestContext.CreateAsync(); GoodClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForTcp(connectionToken: Token) }); await GoodClient.StartAsync(); Port = GoodClient.RuntimePort ?? throw new InvalidOperationException("GoodClient is not using TCP mode; RuntimePort is null"); } public async Task DisposeAsync() { if (GoodClient is not null) { await GoodClient.ForceStopAsync(); } await Ctx.DisposeAsync(); } } public class ConnectionTokenTests : IClassFixture { private readonly ConnectionTokenTestFixture _fixture; public ConnectionTokenTests(ConnectionTokenTestFixture fixture) { _fixture = fixture; } [Fact] public async Task Connects_With_The_Matching_Token() { var pong = await _fixture.GoodClient.PingAsync("hi"); Assert.Equal("pong: hi", pong.Message); } [Fact] public async Task Rejects_A_Wrong_Token() { var wrongClient = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri($"localhost:{_fixture.Port}", connectionToken: "wrong") }); try { var ex = await Assert.ThrowsAnyAsync(() => wrongClient.StartAsync()); Assert.Contains("AUTHENTICATION_FAILED", GetFullMessage(ex)); } finally { // Best-effort cleanup; ignore stop errors when the client failed to start. try { await wrongClient.ForceStopAsync(); } catch (Exception) { } } } [Fact] public async Task Rejects_A_Missing_Token_When_One_Is_Required() { var noTokenClient = new CopilotClient(new CopilotClientOptions { Connection = RuntimeConnection.ForUri($"localhost:{_fixture.Port}") }); try { var ex = await Assert.ThrowsAnyAsync(() => noTokenClient.StartAsync()); Assert.Contains("AUTHENTICATION_FAILED", GetFullMessage(ex)); } finally { // Best-effort cleanup; ignore stop errors when the client failed to start. try { await noTokenClient.ForceStopAsync(); } catch (Exception) { } } } private static string GetFullMessage(Exception ex) { var messages = new List(); for (var cur = ex; cur is not null; cur = cur.InnerException) { messages.Add(cur.Message); } return string.Join(" | ", messages); } } /// /// When the SDK spawns its own CLI in TCP mode without an explicit token, it auto-generates /// a GUID and round-trips it through the spawned CLI. /// public class ConnectionTokenAutoGeneratedTests : IAsyncLifetime { private E2ETestContext _ctx = null!; private CopilotClient _client = null!; public async Task InitializeAsync() { _ctx = await E2ETestContext.CreateAsync(); _client = _ctx.CreateClient(useStdio: false); } public async Task DisposeAsync() { if (_client is not null) { await _client.ForceStopAsync(); } await _ctx.DisposeAsync(); } [Fact] public async Task The_SDK_Auto_Generated_Guid_Round_Trips_Through_The_Spawned_CLI() { await _client.StartAsync(); var pong = await _client.PingAsync("hi"); Assert.Equal("pong: hi", pong.Message); } }