33// See the LICENSE file in the project root for more information
44
55using System . Diagnostics ;
6- using System . Text ;
7- using Elastic . Documentation . Api . Core . AskAi ;
8- using Elastic . Documentation . Api . Core . Telemetry ;
96using Elastic . Documentation . Api . Infrastructure ;
107using Elastic . Documentation . Api . Infrastructure . Aws ;
118using Elastic . Documentation . Api . Infrastructure . OpenTelemetry ;
1411using Microsoft . AspNetCore . Mvc . Testing ;
1512using Microsoft . Extensions . DependencyInjection ;
1613using Microsoft . Extensions . DependencyInjection . Extensions ;
17- using Microsoft . Extensions . Logging ;
1814using OpenTelemetry ;
1915using OpenTelemetry . Logs ;
2016using OpenTelemetry . Trace ;
@@ -24,12 +20,13 @@ namespace Elastic.Documentation.Api.IntegrationTests.Fixtures;
2420/// <summary>
2521/// Custom WebApplicationFactory for testing the API with mocked services.
2622/// This fixture can be reused across multiple test classes.
23+ /// Only mocks services that ALL tests need (OpenTelemetry, AWS Parameters).
24+ /// Test-specific mocks should be configured using WithMockedServices.
2725/// </summary>
2826public class ApiWebApplicationFactory : WebApplicationFactory < Program >
2927{
3028 public List < Activity > ExportedActivities { get ; } = [ ] ;
3129 public List < LogRecord > ExportedLogRecords { get ; } = [ ] ;
32- private readonly List < MemoryStream > _mockMemoryStreams = [ ] ;
3330 private readonly Action < IServiceCollection > ? _configureServices ;
3431
3532 public ApiWebApplicationFactory ( ) : this ( null )
@@ -60,67 +57,31 @@ public static ApiWebApplicationFactory WithMockedServices(Action<IServiceCollect
6057 => new ( configureServices ) ;
6158
6259 protected override void ConfigureWebHost ( IWebHostBuilder builder ) => builder . ConfigureServices ( services =>
63- {
64- var otelBuilder = services . AddOpenTelemetry ( ) ;
65- _ = otelBuilder . WithTracing ( tracing =>
66- {
67- _ = tracing
68- . AddDocsApiTracing ( ) // Reuses production configuration
69- . AddInMemoryExporter ( ExportedActivities ) ;
70- } ) ;
71- _ = otelBuilder . WithLogging ( logging =>
72- {
73- _ = logging
74- . AddDocsApiLogging ( ) // Reuses production configuration
75- . AddInMemoryExporter ( ExportedLogRecords ) ;
76- } ) ;
77-
78- // Mock IParameterProvider to avoid AWS dependencies
79- var mockParameterProvider = A . Fake < IParameterProvider > ( ) ;
80- A . CallTo ( ( ) => mockParameterProvider . GetParam ( A < string > . _ , A < bool > . _ , A < Cancel > . _ ) )
81- . Returns ( Task . FromResult ( "mock-value" ) ) ;
82- _ = services . AddSingleton ( mockParameterProvider ) ;
83-
84- // Mock IAskAiGateway to avoid external AI service calls
85- var mockAskAiGateway = A . Fake < IAskAiGateway < Stream > > ( ) ;
86- A . CallTo ( ( ) => mockAskAiGateway . AskAi ( A < AskAiRequest > . _ , A < Cancel > . _ ) )
87- . ReturnsLazily ( ( ) =>
88- {
89- var stream = new MemoryStream ( Encoding . UTF8 . GetBytes ( "data: test\n \n " ) ) ;
90- _mockMemoryStreams . Add ( stream ) ;
91- return Task . FromResult < Stream > ( stream ) ;
92- } ) ;
93- _ = services . AddSingleton ( mockAskAiGateway ) ;
94-
95- // Mock IStreamTransformer
96- var mockTransformer = A . Fake < IStreamTransformer > ( ) ;
97- A . CallTo ( ( ) => mockTransformer . AgentProvider ) . Returns ( "test-provider" ) ;
98- A . CallTo ( ( ) => mockTransformer . AgentId ) . Returns ( "test-agent" ) ;
99- A . CallTo ( ( ) => mockTransformer . TransformAsync ( A < Stream > . _ , A < string ? > . _ , A < Activity ? > . _ , A < Cancel > . _ ) )
100- . ReturnsLazily ( ( Stream s , string ? _ , Activity ? activity , Cancel _ ) =>
101- {
102- // Dispose the activity if provided (simulating what the real transformer does)
103- activity ? . Dispose ( ) ;
104- return Task . FromResult ( s ) ;
105- } ) ;
106- _ = services . AddSingleton ( mockTransformer ) ;
107-
108- // Allow tests to override services - RemoveAll + Add to properly replace
109- _configureServices ? . Invoke ( services ) ;
110- } ) ;
111-
112- protected override void Dispose ( bool disposing )
11360 {
114- if ( disposing )
61+ // Configure OpenTelemetry with in-memory exporters for all tests
62+ var otelBuilder = services . AddOpenTelemetry ( ) ;
63+ _ = otelBuilder . WithTracing ( tracing =>
11564 {
116- foreach ( var stream in _mockMemoryStreams )
117- {
118- stream . Dispose ( ) ;
119- }
120- _mockMemoryStreams . Clear ( ) ;
121- }
122- base . Dispose ( disposing ) ;
123- }
65+ _ = tracing
66+ . AddDocsApiTracing ( ) // Reuses production configuration
67+ . AddInMemoryExporter ( ExportedActivities ) ;
68+ } ) ;
69+ _ = otelBuilder . WithLogging ( logging =>
70+ {
71+ _ = logging
72+ . AddDocsApiLogging ( ) // Reuses production configuration
73+ . AddInMemoryExporter ( ExportedLogRecords ) ;
74+ } ) ;
75+
76+ // Mock IParameterProvider to avoid AWS dependencies in all tests
77+ var mockParameterProvider = A . Fake < IParameterProvider > ( ) ;
78+ A . CallTo ( ( ) => mockParameterProvider . GetParam ( A < string > . _ , A < bool > . _ , A < Cancel > . _ ) )
79+ . Returns ( Task . FromResult ( "mock-value" ) ) ;
80+ _ = services . AddSingleton ( mockParameterProvider ) ;
81+
82+ // Apply test-specific service replacements (if any)
83+ _configureServices ? . Invoke ( services ) ;
84+ } ) ;
12485}
12586
12687/// <summary>
@@ -183,10 +144,10 @@ public ServiceReplacementBuilder ReplaceSingleton<TService>(TService instance) w
183144 /// Builds the final service configuration action.
184145 /// </summary>
185146 internal Action < IServiceCollection > Build ( ) => services =>
186- {
187- foreach ( var replacement in _replacements )
188- {
189- replacement ( services ) ;
190- }
191- } ;
147+ {
148+ foreach ( var replacement in _replacements )
149+ {
150+ replacement ( services ) ;
151+ }
152+ } ;
192153}
0 commit comments