Skip to content

Commit 6a17e07

Browse files
franklinicclaude
andcommitted
test(configure-coverage): Bucket4 deployment-metadata methods — real wiring verification
Adds 5 integration tests that screen for the "stored-but-never-consumed" pattern on Configure* methods not touched by other in-flight PRs: - ConfigureCaching - ConfigureVersioning - ConfigureABTesting - ConfigureExport - ConfigureGpuDiagnostics Each test sets a NON-DEFAULT sentinel value (MaxCacheSize=99, DefaultVersion="v999-integration-test", DefaultTrafficSplit=0.123, TargetPlatform=TFLite, GpuDiagnosticLevel.Verbose) and asserts that the exact sentinel is observable post-build on result.DeploymentConfiguration (or, for GpuDiagnostics, on the process-wide GpuDiagnosticsConfig static). Stored-but-never-consumed bugs fail because the post-build value would be the type default, not the sentinel. GpuDiagnostics test restores the previous global level in a finally block so it doesn't bleed state into other tests sharing the ConfigureMethodCoverage collection fixture. Scope: skips methods covered by other open PRs (#1361 adversarial, #1362 mixed precision, #1367 model registry, #1351 Adam, #1349 INT8). 5/5 passing in 2s. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 1b898ce commit 6a17e07

1 file changed

Lines changed: 185 additions & 0 deletions

File tree

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
using AiDotNet.Configuration;
2+
using AiDotNet.Deployment.Configuration;
3+
using AiDotNet.Enums;
4+
using Xunit;
5+
using Xunit.Abstractions;
6+
7+
namespace AiDotNet.Tests.IntegrationTests.ConfigureMethodCoverage;
8+
9+
/// <summary>
10+
/// Bucket 4 — Configure* methods whose ONLY observable effect is that the
11+
/// configured value lands on <see cref="AiModelResult{T,TInput,TOutput}.DeploymentConfiguration"/>
12+
/// (or on a process-wide config flag).
13+
/// </summary>
14+
/// <remarks>
15+
/// <para>
16+
/// Each test sets a NON-DEFAULT value on its config (e.g.
17+
/// <c>MaxCacheSize = 99</c>) and asserts that the SAME non-default value
18+
/// is observable on the post-build result. This screens for the systemic
19+
/// "stored on the builder but never consumed" pattern that PR #1357 / #1361
20+
/// found across the Configure* surface.
21+
/// </para>
22+
/// <para>
23+
/// Methods covered (5 of the methods not touched by the other open PRs
24+
/// in flight — #1361 covers AdversarialRobustness, #1362 covers
25+
/// MixedPrecision, #1367 covers ModelRegistry, #1351 covers Adam,
26+
/// #1349/#1363 cover INT8):
27+
/// </para>
28+
/// <list type="bullet">
29+
/// <item>ConfigureCaching</item>
30+
/// <item>ConfigureVersioning</item>
31+
/// <item>ConfigureABTesting</item>
32+
/// <item>ConfigureExport</item>
33+
/// <item>ConfigureGpuDiagnostics</item>
34+
/// </list>
35+
/// </remarks>
36+
[Collection("ConfigureMethodCoverage")]
37+
public class Bucket4_DeploymentMetadataTests : ConfigureMethodTestBase
38+
{
39+
private readonly ITestOutputHelper _output;
40+
public Bucket4_DeploymentMetadataTests(ITestOutputHelper output) { _output = output; }
41+
42+
/// <summary>
43+
/// ConfigureCaching — a non-default <c>MaxCacheSize</c> set via
44+
/// <c>ConfigureCaching</c> MUST land on <c>result.DeploymentConfiguration.Caching.MaxCacheSize</c>
45+
/// after BuildAsync. Verifies the field flows through
46+
/// <c>DeploymentConfiguration.Create</c> into the result instead of being
47+
/// silently dropped.
48+
/// </summary>
49+
[Fact]
50+
[Trait("category", "integration-configure-method")]
51+
public async Task ConfigureCaching_NonDefaultValue_LandsOnDeploymentConfiguration()
52+
{
53+
const int sentinel = 99;
54+
var (features, labels) = MakeMemorizationSet();
55+
var loader = MakeCanaryLoader(features, labels);
56+
var model = MakeCanaryModel();
57+
58+
var cacheCfg = new CacheConfig { MaxCacheSize = sentinel };
59+
var result = await new AiModelBuilder<float, Tensor<float>, Tensor<float>>()
60+
.ConfigureModel(model)
61+
.ConfigureDataLoader(loader)
62+
.ConfigureCaching(cacheCfg)
63+
.BuildAsync();
64+
65+
Assert.NotNull(result.DeploymentConfiguration);
66+
Assert.NotNull(result.DeploymentConfiguration!.Caching);
67+
Assert.Equal(sentinel, result.DeploymentConfiguration.Caching!.MaxCacheSize);
68+
}
69+
70+
/// <summary>
71+
/// ConfigureVersioning — a non-default <c>DefaultVersion</c> set via
72+
/// <c>ConfigureVersioning</c> MUST land on
73+
/// <c>result.DeploymentConfiguration.Versioning.DefaultVersion</c>.
74+
/// </summary>
75+
[Fact]
76+
[Trait("category", "integration-configure-method")]
77+
public async Task ConfigureVersioning_NonDefaultValue_LandsOnDeploymentConfiguration()
78+
{
79+
const string sentinel = "v999-integration-test";
80+
var (features, labels) = MakeMemorizationSet();
81+
var loader = MakeCanaryLoader(features, labels);
82+
var model = MakeCanaryModel();
83+
84+
var versCfg = new VersioningConfig { DefaultVersion = sentinel };
85+
var result = await new AiModelBuilder<float, Tensor<float>, Tensor<float>>()
86+
.ConfigureModel(model)
87+
.ConfigureDataLoader(loader)
88+
.ConfigureVersioning(versCfg)
89+
.BuildAsync();
90+
91+
Assert.NotNull(result.DeploymentConfiguration);
92+
Assert.NotNull(result.DeploymentConfiguration!.Versioning);
93+
Assert.Equal(sentinel, result.DeploymentConfiguration.Versioning!.DefaultVersion);
94+
}
95+
96+
/// <summary>
97+
/// ConfigureABTesting — a non-default <c>DefaultTrafficSplit</c> set via
98+
/// <c>ConfigureABTesting</c> MUST land on
99+
/// <c>result.DeploymentConfiguration.ABTesting.DefaultTrafficSplit</c>.
100+
/// </summary>
101+
[Fact]
102+
[Trait("category", "integration-configure-method")]
103+
public async Task ConfigureABTesting_NonDefaultValue_LandsOnDeploymentConfiguration()
104+
{
105+
const double sentinel = 0.123;
106+
var (features, labels) = MakeMemorizationSet();
107+
var loader = MakeCanaryLoader(features, labels);
108+
var model = MakeCanaryModel();
109+
110+
var abCfg = new ABTestingConfig { Enabled = true, DefaultTrafficSplit = sentinel };
111+
var result = await new AiModelBuilder<float, Tensor<float>, Tensor<float>>()
112+
.ConfigureModel(model)
113+
.ConfigureDataLoader(loader)
114+
.ConfigureABTesting(abCfg)
115+
.BuildAsync();
116+
117+
Assert.NotNull(result.DeploymentConfiguration);
118+
Assert.NotNull(result.DeploymentConfiguration!.ABTesting);
119+
Assert.Equal(sentinel, result.DeploymentConfiguration.ABTesting!.DefaultTrafficSplit);
120+
}
121+
122+
/// <summary>
123+
/// ConfigureExport — a non-default <c>TargetPlatform</c> set via
124+
/// <c>ConfigureExport</c> MUST land on
125+
/// <c>result.DeploymentConfiguration.Export.TargetPlatform</c>. Verifies
126+
/// the export config flows into the result so downstream
127+
/// <c>ExportToOnnx</c> / <c>ExportToCoreML</c> / etc. methods see it.
128+
/// </summary>
129+
[Fact]
130+
[Trait("category", "integration-configure-method")]
131+
public async Task ConfigureExport_NonDefaultTarget_LandsOnDeploymentConfiguration()
132+
{
133+
const TargetPlatform sentinel = TargetPlatform.TFLite;
134+
var (features, labels) = MakeMemorizationSet();
135+
var loader = MakeCanaryLoader(features, labels);
136+
var model = MakeCanaryModel();
137+
138+
var expCfg = new ExportConfig { TargetPlatform = sentinel };
139+
var result = await new AiModelBuilder<float, Tensor<float>, Tensor<float>>()
140+
.ConfigureModel(model)
141+
.ConfigureDataLoader(loader)
142+
.ConfigureExport(expCfg)
143+
.BuildAsync();
144+
145+
Assert.NotNull(result.DeploymentConfiguration);
146+
Assert.NotNull(result.DeploymentConfiguration!.Export);
147+
Assert.Equal(sentinel, result.DeploymentConfiguration.Export!.TargetPlatform);
148+
}
149+
150+
/// <summary>
151+
/// ConfigureGpuDiagnostics — sets the process-wide
152+
/// <c>GpuDiagnosticsConfig.Level</c>. Picks <c>Verbose</c> as the
153+
/// sentinel because the test fixture's CPU-mode default leaves
154+
/// <c>Level</c> at <c>Silent</c>; asserts the explicit Configure call
155+
/// flipped the global to the requested value.
156+
/// </summary>
157+
[Fact]
158+
[Trait("category", "integration-configure-method")]
159+
public async Task ConfigureGpuDiagnostics_LevelOverride_AppliesToGlobalConfig()
160+
{
161+
const GpuDiagnosticLevel sentinel = GpuDiagnosticLevel.Verbose;
162+
var (features, labels) = MakeMemorizationSet();
163+
var loader = MakeCanaryLoader(features, labels);
164+
var model = MakeCanaryModel();
165+
166+
var previous = GpuDiagnosticsConfig.Level;
167+
try
168+
{
169+
var diag = new GpuDiagnosticsOptions { Level = sentinel };
170+
var result = await new AiModelBuilder<float, Tensor<float>, Tensor<float>>()
171+
.ConfigureModel(model)
172+
.ConfigureDataLoader(loader)
173+
.ConfigureGpuDiagnostics(diag)
174+
.BuildAsync();
175+
176+
Assert.Equal(sentinel, GpuDiagnosticsConfig.Level);
177+
}
178+
finally
179+
{
180+
// Restore the previous global so we don't bleed state into
181+
// other tests that read GpuDiagnosticsConfig.Level.
182+
GpuDiagnosticsConfig.Level = previous;
183+
}
184+
}
185+
}

0 commit comments

Comments
 (0)