-
Notifications
You must be signed in to change notification settings - Fork 285
Fix missing MCP test #2925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix missing MCP test #2925
Changes from all commits
52b53ef
de28682
80e6b2e
8fae2b8
ccab7f1
edd0943
5db169f
adc89d2
39647da
676d70c
98a18af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Collections.Specialized; | ||
| using System.Configuration; | ||
| using System.IdentityModel.Tokens.Jwt; | ||
| using System.IO; | ||
| using System.IO.Abstractions; | ||
|
|
@@ -1128,7 +1129,7 @@ public async Task TestSqlSettingPostStartupConfigurations(string configurationEn | |
| await httpClient.GetAsync($"/{OPENAPI_SWAGGER_ENDPOINT}"); | ||
| Assert.AreEqual(HttpStatusCode.ServiceUnavailable, preConfigOpenApiSwaggerEndpointAvailability.StatusCode); | ||
|
|
||
| HttpStatusCode responseCode = await HydratePostStartupConfiguration(httpClient, content, configurationEndpoint); | ||
| HttpStatusCode responseCode = await HydratePostStartupConfiguration(httpClient, content, configurationEndpoint, configuration.Runtime.Rest); | ||
|
|
||
| // When the authorization resolver is properly configured, authorization will have failed | ||
| // because no auth headers are present. | ||
|
|
@@ -2528,26 +2529,37 @@ public async Task TestRuntimeBaseRouteInNextLinkForPaginatedRestResponse() | |
| /// <param name="expectedStatusCodeForGraphQL">Expected HTTP status code code for the GraphQL request</param> | ||
| [DataTestMethod] | ||
| [TestCategory(TestCategory.MSSQL)] | ||
| [DataRow(true, true, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Both Rest and GraphQL endpoints enabled globally")] | ||
| [DataRow(true, false, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest enabled and GraphQL endpoints disabled globally")] | ||
| [DataRow(false, true, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest disabled and GraphQL endpoints enabled globally")] | ||
| [DataRow(true, true, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Both Rest and GraphQL endpoints enabled globally")] | ||
| [DataRow(true, false, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest enabled and GraphQL endpoints disabled globally")] | ||
| [DataRow(false, true, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest disabled and GraphQL endpoints enabled globally")] | ||
| public async Task TestGlobalFlagToEnableRestAndGraphQLForHostedAndNonHostedEnvironment( | ||
| [DataRow(true, true, true, HttpStatusCode.OK, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest, GraphQL, and MCP enabled globally")] | ||
| [DataRow(true, true, false, HttpStatusCode.OK, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest and GraphQL enabled, MCP disabled globally")] | ||
| [DataRow(true, false, true, HttpStatusCode.OK, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest enabled, GraphQL disabled, and MCP enabled globally")] | ||
| [DataRow(true, false, false, HttpStatusCode.OK, HttpStatusCode.NotFound, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest enabled, GraphQL and MCP disabled globally")] | ||
| [DataRow(false, true, true, HttpStatusCode.NotFound, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest disabled, GraphQL and MCP enabled globally")] | ||
| [DataRow(false, true, false, HttpStatusCode.NotFound, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest disabled, GraphQL enabled, and MCP disabled globally")] | ||
| [DataRow(false, false, true, HttpStatusCode.NotFound, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT, DisplayName = "V1 - Rest and GraphQL disabled, MCP enabled globally")] | ||
| [DataRow(true, true, true, HttpStatusCode.OK, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest, GraphQL, and MCP enabled globally")] | ||
| [DataRow(true, true, false, HttpStatusCode.OK, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest and GraphQL enabled, MCP disabled globally")] | ||
| [DataRow(true, false, true, HttpStatusCode.OK, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest enabled, GraphQL disabled, and MCP enabled globally")] | ||
| [DataRow(true, false, false, HttpStatusCode.OK, HttpStatusCode.NotFound, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest enabled, GraphQL and MCP disabled globally")] | ||
| [DataRow(false, true, true, HttpStatusCode.NotFound, HttpStatusCode.OK, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest disabled, GraphQL and MCP enabled globally")] | ||
| [DataRow(false, true, false, HttpStatusCode.NotFound, HttpStatusCode.OK, HttpStatusCode.NotFound, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest disabled, GraphQL enabled, and MCP disabled globally")] | ||
| [DataRow(false, false, true, HttpStatusCode.NotFound, HttpStatusCode.NotFound, HttpStatusCode.OK, CONFIGURATION_ENDPOINT_V2, DisplayName = "V2 - Rest and GraphQL disabled, MCP enabled globally")] | ||
| public async Task TestGlobalFlagToEnableRestGraphQLAndMcpForHostedAndNonHostedEnvironment( | ||
| bool isRestEnabled, | ||
| bool isGraphQLEnabled, | ||
| bool isMcpEnabled, | ||
| HttpStatusCode expectedStatusCodeForREST, | ||
| HttpStatusCode expectedStatusCodeForGraphQL, | ||
| HttpStatusCode expectedStatusCodeForMcp, | ||
| string configurationEndpoint) | ||
| { | ||
| GraphQLRuntimeOptions graphqlOptions = new(Enabled: isGraphQLEnabled); | ||
| RestRuntimeOptions restRuntimeOptions = new(Enabled: isRestEnabled); | ||
| McpRuntimeOptions mcpRuntimeOptions = new(Enabled: isMcpEnabled); | ||
|
|
||
| DataSource dataSource = new(DatabaseType.MSSQL, | ||
| GetConnectionStringFromEnvironmentConfig(environment: TestCategory.MSSQL), Options: null); | ||
|
|
||
| RuntimeConfig configuration = InitMinimalRuntimeConfig(dataSource, graphqlOptions, restRuntimeOptions, null); | ||
| RuntimeConfig configuration = InitMinimalRuntimeConfig(dataSource, graphqlOptions, restRuntimeOptions, mcpRuntimeOptions); | ||
| const string CUSTOM_CONFIG = "custom-config.json"; | ||
| File.WriteAllText(CUSTOM_CONFIG, configuration.ToJson()); | ||
|
|
||
|
|
@@ -2570,17 +2582,35 @@ public async Task TestGlobalFlagToEnableRestAndGraphQLForHostedAndNonHostedEnvir | |
|
|
||
| object payload = new { query }; | ||
|
|
||
| HttpRequestMessage graphQLRequest = new(HttpMethod.Post, "/graphql") | ||
| // GraphQL request | ||
| HttpRequestMessage graphQLRequest = new(HttpMethod.Post, configuration.Runtime.GraphQL.Path) | ||
| { | ||
| Content = JsonContent.Create(payload) | ||
| }; | ||
|
|
||
| HttpResponseMessage graphQLResponse = await client.SendAsync(graphQLRequest); | ||
| Assert.AreEqual(expectedStatusCodeForGraphQL, graphQLResponse.StatusCode); | ||
| Assert.AreEqual(expectedStatusCodeForGraphQL, graphQLResponse.StatusCode, "The GraphQL response is different from the expected result."); | ||
|
|
||
| HttpRequestMessage restRequest = new(HttpMethod.Get, "/api/Book"); | ||
| // REST request | ||
| HttpRequestMessage restRequest = new(HttpMethod.Get, $"{configuration.Runtime.Rest.Path}/Book"); | ||
| HttpResponseMessage restResponse = await client.SendAsync(restRequest); | ||
| Assert.AreEqual(expectedStatusCodeForREST, restResponse.StatusCode); | ||
| Assert.AreEqual(expectedStatusCodeForREST, restResponse.StatusCode, "The REST response is different from the expected result."); | ||
|
|
||
| // MCP request | ||
| await Task.Delay(2000); | ||
| object mcpPayload = new | ||
| { | ||
| jsonrpc = "2.0", | ||
| id = 1, | ||
| method = "tools/list" | ||
| }; | ||
| HttpRequestMessage mcpRequest = new(HttpMethod.Post, configuration.Runtime.Mcp.Path) | ||
| { | ||
| Content = JsonContent.Create(mcpPayload) | ||
| }; | ||
| mcpRequest.Headers.Add("Accept", "*/*"); | ||
| HttpResponseMessage mcpResponse = await client.SendAsync(mcpRequest); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why cant we use the same |
||
| Assert.AreEqual(expectedStatusCodeForMcp, mcpResponse.StatusCode, "The MCP response is different from the expected result."); | ||
| } | ||
|
|
||
| // Hosted Scenario | ||
|
|
@@ -2590,18 +2620,17 @@ public async Task TestGlobalFlagToEnableRestAndGraphQLForHostedAndNonHostedEnvir | |
| { | ||
| JsonContent content = GetPostStartupConfigParams(MSSQL_ENVIRONMENT, configuration, configurationEndpoint); | ||
|
|
||
| HttpResponseMessage postResult = | ||
| await client.PostAsync(configurationEndpoint, content); | ||
| Assert.AreEqual(HttpStatusCode.OK, postResult.StatusCode); | ||
| HttpResponseMessage postResult = await client.PostAsync(configurationEndpoint, content); | ||
| Assert.AreEqual(HttpStatusCode.OK, postResult.StatusCode, "The hydration post-response is different from the expected result."); | ||
|
|
||
| HttpStatusCode restResponseCode = await GetRestResponsePostConfigHydration(client); | ||
| HttpStatusCode restResponseCode = await GetRestResponsePostConfigHydration(client, configuration.Runtime.Rest); | ||
| Assert.AreEqual(expected: expectedStatusCodeForREST, actual: restResponseCode, "The REST hydration post-response is different from the expected result."); | ||
|
|
||
| Assert.AreEqual(expected: expectedStatusCodeForREST, actual: restResponseCode); | ||
|
|
||
| HttpStatusCode graphqlResponseCode = await GetGraphQLResponsePostConfigHydration(client); | ||
|
|
||
| Assert.AreEqual(expected: expectedStatusCodeForGraphQL, actual: graphqlResponseCode); | ||
| HttpStatusCode graphqlResponseCode = await GetGraphQLResponsePostConfigHydration(client, configuration.Runtime.GraphQL); | ||
| Assert.AreEqual(expected: expectedStatusCodeForGraphQL, actual: graphqlResponseCode, "The GraphQL hydration post-response is different from the expected result."); | ||
|
|
||
| HttpStatusCode mcpResponseCode = await GetMcpResponsePostConfigHydration(client, configuration.Runtime.Mcp); | ||
| Assert.AreEqual(expected: expectedStatusCodeForMcp, actual: mcpResponseCode, "The MCP hydration post-response is different from the expected result."); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -3646,7 +3675,7 @@ public async Task TestSchemaIntrospectionQuery(bool enableIntrospection, bool ex | |
| using (HttpClient client = server.CreateClient()) | ||
| { | ||
| JsonContent content = GetPostStartupConfigParams(MSSQL_ENVIRONMENT, configuration, configurationEndpoint); | ||
| HttpStatusCode responseCode = await HydratePostStartupConfiguration(client, content, configurationEndpoint); | ||
| HttpStatusCode responseCode = await HydratePostStartupConfiguration(client, content, configurationEndpoint, configuration.Runtime.Rest); | ||
|
|
||
| Assert.AreEqual(expected: HttpStatusCode.OK, actual: responseCode, message: "Configuration hydration failed."); | ||
|
|
||
|
|
@@ -5243,14 +5272,14 @@ private static JsonContent GetPostStartupConfigParams(string environment, Runtim | |
| /// <param name="httpClient">Client used for request execution.</param> | ||
| /// <param name="config">Post-startup configuration</param> | ||
| /// <returns>ServiceUnavailable if service is not successfully hydrated with config</returns> | ||
| private static async Task<HttpStatusCode> HydratePostStartupConfiguration(HttpClient httpClient, JsonContent content, string configurationEndpoint) | ||
| private static async Task<HttpStatusCode> HydratePostStartupConfiguration(HttpClient httpClient, JsonContent content, string configurationEndpoint, RestRuntimeOptions rest) | ||
| { | ||
| // Hydrate configuration post-startup | ||
| HttpResponseMessage postResult = | ||
| await httpClient.PostAsync(configurationEndpoint, content); | ||
| Assert.AreEqual(HttpStatusCode.OK, postResult.StatusCode); | ||
|
|
||
| return await GetRestResponsePostConfigHydration(httpClient); | ||
| return await GetRestResponsePostConfigHydration(httpClient, rest); | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -5259,7 +5288,7 @@ private static async Task<HttpStatusCode> HydratePostStartupConfiguration(HttpCl | |
| /// <param name="httpClient">Client used for request execution.</param> | ||
| /// <returns>ServiceUnavailable if service is not successfully hydrated with config, | ||
| /// else the response code from the REST request</returns> | ||
| private static async Task<HttpStatusCode> GetRestResponsePostConfigHydration(HttpClient httpClient) | ||
| private static async Task<HttpStatusCode> GetRestResponsePostConfigHydration(HttpClient httpClient, RestRuntimeOptions rest) | ||
| { | ||
| // Retry request RETRY_COUNT times in 1 second increments to allow required services | ||
| // time to instantiate and hydrate permissions. | ||
|
|
@@ -5269,7 +5298,7 @@ private static async Task<HttpStatusCode> GetRestResponsePostConfigHydration(Htt | |
| { | ||
| // Spot test authorization resolver utilization to ensure configuration is used. | ||
| HttpResponseMessage postConfigHydrationResult = | ||
| await httpClient.GetAsync($"api/{POST_STARTUP_CONFIG_ENTITY}"); | ||
| await httpClient.GetAsync($"{rest.Path}/{POST_STARTUP_CONFIG_ENTITY}"); | ||
| responseCode = postConfigHydrationResult.StatusCode; | ||
|
|
||
| if (postConfigHydrationResult.StatusCode == HttpStatusCode.ServiceUnavailable) | ||
|
|
@@ -5291,7 +5320,7 @@ private static async Task<HttpStatusCode> GetRestResponsePostConfigHydration(Htt | |
| /// <param name="httpClient">Client used for request execution.</param> | ||
| /// <returns>ServiceUnavailable if service is not successfully hydrated with config, | ||
| /// else the response code from the GRAPHQL request</returns> | ||
| private static async Task<HttpStatusCode> GetGraphQLResponsePostConfigHydration(HttpClient httpClient) | ||
| private static async Task<HttpStatusCode> GetGraphQLResponsePostConfigHydration(HttpClient httpClient, GraphQLRuntimeOptions graphQL) | ||
| { | ||
| // Retry request RETRY_COUNT times in 1 second increments to allow required services | ||
| // time to instantiate and hydrate permissions. | ||
|
|
@@ -5309,7 +5338,7 @@ private static async Task<HttpStatusCode> GetGraphQLResponsePostConfigHydration( | |
|
|
||
| object payload = new { query }; | ||
|
|
||
| HttpRequestMessage graphQLRequest = new(HttpMethod.Post, "/graphql") | ||
| HttpRequestMessage graphQLRequest = new(HttpMethod.Post, graphQL.Path) | ||
| { | ||
| Content = JsonContent.Create(payload) | ||
| }; | ||
|
|
@@ -5330,6 +5359,49 @@ private static async Task<HttpStatusCode> GetGraphQLResponsePostConfigHydration( | |
| return responseCode; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Executing MCP POST requests against the engine until a non-503 error is received. | ||
| /// </summary> | ||
| /// <param name="httpClient">Client used for request execution.</param> | ||
| /// <returns>ServiceUnavailable if service is not successfully hydrated with config, | ||
| /// else the response code from the MCP request</returns> | ||
| private static async Task<HttpStatusCode> GetMcpResponsePostConfigHydration(HttpClient httpClient, McpRuntimeOptions mcp) | ||
| { | ||
| // Retry request RETRY_COUNT times in 1 second increments to allow required services | ||
| // time to instantiate and hydrate permissions. | ||
| int retryCount = RETRY_COUNT; | ||
| HttpStatusCode responseCode = HttpStatusCode.ServiceUnavailable; | ||
| while (retryCount > 0) | ||
| { | ||
| // Minimal MCP request (list tools) – valid JSON-RPC request | ||
| object payload = new | ||
| { | ||
| jsonrpc = "2.0", | ||
| id = 1, | ||
| method = "tools/list" | ||
| }; | ||
| HttpRequestMessage mcpRequest = new(HttpMethod.Post, mcp.Path) | ||
| { | ||
| Content = JsonContent.Create(payload) | ||
| }; | ||
| mcpRequest.Headers.Add("Accept", "*/*"); | ||
|
|
||
| HttpResponseMessage mcpResponse = await httpClient.SendAsync(mcpRequest); | ||
| responseCode = mcpResponse.StatusCode; | ||
|
|
||
| if (responseCode == HttpStatusCode.ServiceUnavailable || responseCode == HttpStatusCode.NotFound) | ||
| { | ||
| retryCount--; | ||
| Thread.Sleep(TimeSpan.FromSeconds(RETRY_WAIT_SECONDS)); | ||
| continue; | ||
|
Comment on lines
+5395
to
+5396
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function is asynchronous but using |
||
| } | ||
|
|
||
| break; | ||
| } | ||
|
|
||
| return responseCode; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Helper method to instantiate RuntimeConfig object needed for multiple create tests. | ||
| /// </summary> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we add a try-wait condition (within a limit- 5 seconds?) until he
/mcpendpoint is available instead of hard-coded 2 seconds of wait?