diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 84576fed620..c78607a1607 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "dotnet-coverage": { - "version": "18.7.0", + "version": "18.9.0", "commands": [ "dotnet-coverage" ] @@ -21,10 +21,10 @@ ] }, "PowerShell": { - "version": "7.6.2", + "version": "7.6.3", "commands": [ "pwsh" ] } } -} +} \ No newline at end of file diff --git a/.github/skills/prepare-release/SKILL.md b/.github/skills/prepare-release/SKILL.md index 33f30dbff05..df9f755c03b 100644 --- a/.github/skills/prepare-release/SKILL.md +++ b/.github/skills/prepare-release/SKILL.md @@ -3,127 +3,31 @@ name: prepare-release description: Prepares the repository for an internal release branch. Use this when asked to "prepare for a release", "prepare internal release branch", or similar release preparation tasks. --- -# Prepare Internal Release Branch +# Prepare Release -When preparing a public branch for internal release, apply the following changes: +Prepares a `dotnet/extensions` public release branch (`release/.`) for the internal release process on the corresponding `internal/release/.` branch. -## 1. Directory.Build.props +The preparation is organized into ordered stages. Work through them in sequence, loading each stage's reference file only when you reach that stage. -Add NU1507 warning suppression after the `TestNetCoreTargetFrameworks` PropertyGroup. Internal branches don't use package source mapping due to internal feeds: +## Stage workflow -```xml - - - $(NoWarn);NU1507 - -``` +Complete stages strictly in order. Treat each stage -- and each sub-stage of a stage that has them -- as an independent, committable unit. For every stage or sub-stage: -Insert this new PropertyGroup right after the closing `` that contains `TestNetCoreTargetFrameworks`. +1. Apply the changes described in the stage's reference file. +2. Prompt the user to review the changes (summarize what changed and show the diff), unless the stage's reference file directs you to commit automatically. +3. Wait for the user's approval before committing, unless the stage's reference file directs automatic commits. +4. Create a single commit that contains only that stage's (or sub-stage's) changes. -## 2. NuGet.config +Every stage gets its own commit, and every sub-stage gets its own commit. Never combine multiple stages or sub-stages into a single commit. Never push until the user explicitly instructs it, whatever a stage's commit cadence. -Remove the entire `` section. This section looks like: +## Stage 1 - Prepare Internal Branch -```xml - - - - - - - - - - -``` +Apply the internal-release infrastructure changes to the branch: suppress `NU1507`, remove the NuGet package source mapping, switch on stable/release versioning, add private-feed credential setup to the build template, comment out integration tests, and remove the code-coverage pipeline stage. Never change version numbers here -- those flow via Dependency Flow automation. -**Important**: Do NOT add new internal feed sources to NuGet.config - those are managed by Dependency Flow automation and will be added automatically. +Read and follow [references/stage-1-prepare-internal-branch.md](references/stage-1-prepare-internal-branch.md). -## 3. eng/Versions.props +## Stage 2 - Update Dependencies -Update these two properties (do NOT change any version numbers): +Update the branch's product dependencies to the pending .NET 9, .NET 8, and .NET 10 servicing releases using `darc update-dependencies`. The BAR build IDs come from the release.dot.net Release Tracker, which is behind Microsoft auth and unreachable by the agent, so the user supplies them (pasted `ReleaseManifest.json` or a downloaded copy). This stage has three sub-stages, each its own commit: .NET 9, then .NET 8, then .NET 10. -Change `StabilizePackageVersion` from `false` to `true`: -```xml -true -``` - -Change `DotNetFinalVersionKind` from empty to `release`: -```xml -release -``` - -## 4. eng/pipelines/templates/BuildAndTest.yml - -### Add Private Feeds Credentials Setup - -After the Node.js setup task (the `NodeTool@0` task), add these two tasks to authenticate with private Azure DevOps feeds: - -```yaml - - task: PowerShell@2 - displayName: Setup Private Feeds Credentials - condition: eq(variables['Agent.OS'], 'Windows_NT') - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1 - arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token - env: - Token: $(dn-bot-dnceng-artifact-feeds-rw) - - - task: Bash@3 - displayName: Setup Private Feeds Credentials - condition: ne(variables['Agent.OS'], 'Windows_NT') - inputs: - filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh - arguments: $(Build.SourcesDirectory)/NuGet.config $Token - env: - Token: $(dn-bot-dnceng-artifact-feeds-rw) -``` - -### Comment Out Integration Tests - -Comment out the integration tests step as they require authentication to private feeds that isn't available during internal release builds: - -```yaml - - ${{ if ne(parameters.skipTests, 'true') }}: - # Skipping integration tests for now as they require authentication to the private feeds - # - script: ${{ parameters.buildScript }} - # -integrationTest - # -configuration ${{ parameters.buildConfig }} - # -warnAsError 1 - # /bl:${{ parameters.repoLogPath }}/integration_tests.binlog - # $(_OfficialBuildIdArgs) - # displayName: Run integration tests -``` - -## 5. azure-pipelines.yml - -Remove the `codecoverage` stage entirely. This is the stage that: -- Has `displayName: CodeCoverage` -- Downloads code coverage reports from build jobs -- Merges and validates combined test coverage -- Contains a `CodeCoverageReport` job - -Also remove the `codecoverage` dependency from the post-build validation's `validateDependsOn` list: - -```yaml -# Remove this conditional dependency block: -- ${{ if eq(parameters.runTests, true) }}: - - codecoverage -``` - -## Files NOT to modify - -- **eng/Version.Details.xml**: Version updates are managed by Dependency Flow automation -- **eng/Versions.props version numbers**: Package versions are managed by Dependency Flow automation -- **NuGet.config feed sources**: Internal darc feeds are added automatically by Dependency Flow - -## Summary - -| File | Action | -|------|--------| -| Directory.Build.props | Add `NU1507` to `NoWarn` in new PropertyGroup | -| NuGet.config | Remove entire `` section | -| eng/Versions.props | Set `StabilizePackageVersion=true`, `DotNetFinalVersionKind=release` | -| eng/pipelines/templates/BuildAndTest.yml | Add private feeds credentials setup tasks, comment out integration tests | -| azure-pipelines.yml | Remove `codecoverage` stage and its post-build dependency | +Read and follow [references/stage-2-update-dependencies.md](references/stage-2-update-dependencies.md). diff --git a/.github/skills/prepare-release/references/stage-1-prepare-internal-branch.md b/.github/skills/prepare-release/references/stage-1-prepare-internal-branch.md new file mode 100644 index 00000000000..71870d89a8b --- /dev/null +++ b/.github/skills/prepare-release/references/stage-1-prepare-internal-branch.md @@ -0,0 +1,124 @@ +# Stage 1 - Prepare Internal Branch + +When preparing a public branch for internal release, apply the following changes: + +## 1. Directory.Build.props + +Add NU1507 warning suppression after the `TestNetCoreTargetFrameworks` PropertyGroup. Internal branches don't use package source mapping due to internal feeds: + +```xml + + + $(NoWarn);NU1507 + +``` + +Insert this new PropertyGroup right after the closing `` that contains `TestNetCoreTargetFrameworks`. + +## 2. NuGet.config + +Remove the entire `` section. This section looks like: + +```xml + + + + + + + + + + +``` + +**Important**: Do NOT add new internal feed sources to NuGet.config - those are managed by Dependency Flow automation and will be added automatically. + +## 3. eng/Versions.props + +Update these two properties (do NOT change any version numbers): + +Change `StabilizePackageVersion` from `false` to `true`: +```xml +true +``` + +Change `DotNetFinalVersionKind` from empty to `release`: +```xml +release +``` + +## 4. eng/pipelines/templates/BuildAndTest.yml + +### Add Private Feeds Credentials Setup + +After the Node.js setup task (the `NodeTool@0` task), add these two tasks to authenticate with private Azure DevOps feeds: + +```yaml + - task: PowerShell@2 + displayName: Setup Private Feeds Credentials + condition: eq(variables['Agent.OS'], 'Windows_NT') + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1 + arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) + + - task: Bash@3 + displayName: Setup Private Feeds Credentials + condition: ne(variables['Agent.OS'], 'Windows_NT') + inputs: + filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh + arguments: $(Build.SourcesDirectory)/NuGet.config $Token + env: + Token: $(dn-bot-dnceng-artifact-feeds-rw) +``` + +### Comment Out Integration Tests + +Comment out the integration tests step as they require authentication to private feeds that isn't available during internal release builds: + +```yaml + - ${{ if ne(parameters.skipTests, 'true') }}: + # Skipping integration tests for now as they require authentication to the private feeds + # - script: ${{ parameters.buildScript }} + # -integrationTest + # -configuration ${{ parameters.buildConfig }} + # -warnAsError 1 + # /bl:${{ parameters.repoLogPath }}/integration_tests.binlog + # $(_OfficialBuildIdArgs) + # displayName: Run integration tests +``` + +## 5. azure-pipelines.yml + +Remove the `codecoverage` stage entirely. This is the stage that: +- Has `displayName: CodeCoverage` +- Downloads code coverage reports from build jobs +- Merges and validates combined test coverage +- Contains a `CodeCoverageReport` job + +Also remove the `codecoverage` dependency from the post-build validation's `validateDependsOn` list: + +```yaml +# Remove this conditional dependency block: +- ${{ if eq(parameters.runTests, true) }}: + - codecoverage +``` + +## Files NOT to modify + +- **eng/Version.Details.xml**: Version updates are managed by Dependency Flow automation +- **eng/Versions.props version numbers**: Package versions are managed by Dependency Flow automation +- **NuGet.config feed sources**: Internal darc feeds are added automatically by Dependency Flow + +## Summary + +| File | Action | +|------|--------| +| Directory.Build.props | Add `NU1507` to `NoWarn` in new PropertyGroup | +| NuGet.config | Remove entire `` section | +| eng/Versions.props | Set `StabilizePackageVersion=true`, `DotNetFinalVersionKind=release` | +| eng/pipelines/templates/BuildAndTest.yml | Add private feeds credentials setup tasks, comment out integration tests | +| azure-pipelines.yml | Remove `codecoverage` stage and its post-build dependency | diff --git a/.github/skills/prepare-release/references/stage-2-update-dependencies.md b/.github/skills/prepare-release/references/stage-2-update-dependencies.md new file mode 100644 index 00000000000..6c9ab286dfe --- /dev/null +++ b/.github/skills/prepare-release/references/stage-2-update-dependencies.md @@ -0,0 +1,135 @@ +# Stage 2 - Update Dependencies + +Update the internal release branch's product dependencies to the pending .NET 9, .NET 8, and .NET 10 servicing releases using `darc update-dependencies` against Build Asset Registry (BAR) build IDs. + +This stage has three sub-stages. Run them in order, and give each its own commit: + +1. Update Dependencies: .NET 9 +2. Update Dependencies: .NET 8 +3. Update Dependencies: .NET 10 + +Commit each sub-stage automatically as you complete it -- do not pause for per-sub-stage review or approval. This overrides steps 2 and 3 of the Stage workflow in `SKILL.md`. Pushing remains a separate, user-directed step: do not push until the user explicitly instructs it (see "After the stage"). + +Before committing each sub-stage, review the diff yourself and revert any incidental, non-dependency changes darc introduces (for example, darc sometimes adds a trailing newline to `.config/dotnet-tools.json`). Keep only the intended dependency edits for that sub-stage. + +## Prerequisites + +- Confirm the working tree is clean and you are on the `stage-release-.` branch. +- `darc` must be installed and authenticated against BAR: + - If `darc` is not on the PATH, run `eng/common/darc-init.ps1` (Windows) or `eng/common/darc-init.sh`. + - If darc commands fail with authentication errors, ask the user to run `darc authenticate` and supply a valid BAR token. Never store, echo, or commit tokens. + +## Gathering the BAR build IDs (release.dot.net) + +The Release Tracker at is a Blazor WebAssembly app behind Microsoft (MSAL) authentication. The agent cannot reach or render it, so the **user** provides the inputs. + +**Collect the inputs for all three sub-stages up front, in a single prompt, before running any `darc` commands.** For each pending release, the user opens it on the Release Tracker, clicks its `{}` artifacts link, and opens `manifests/ReleaseManifest.json`. Accept each one either pasted into the chat or as a local path to a downloaded copy: + +- **.NET 9** -- the pending 9.0 release's `manifests/ReleaseManifest.json`. +- **.NET 8** -- the pending 8.0 release's `manifests/ReleaseManifest.json`. +- **.NET 10** -- the pending 10.0 release's `manifests/ReleaseManifest.json`, or a pasted list of its BAR build IDs from the release page. + +Each build entry in a `ReleaseManifest.json` has a `repo` (like `https://dev.azure.com/dnceng/internal/_git/dotnet-`) and a `barBuildId`. Read the IDs you need: + +- **.NET 9 and .NET 8:** the `barBuildId` for `dotnet-runtime`, `dotnet-aspnetcore`, and `dotnet-efcore`. +- **.NET 10:** every `barBuildId` (or the pasted list). Order does not matter. + +Validate every ID with `darc get-build --id ` before applying it, and confirm the repository and commit look correct. If an ID does not resolve, stop and ask the user. + +## Sub-stage 1 - Update Dependencies: .NET 9 + +For each of `dotnet-runtime`, `dotnet-aspnetcore`, and `dotnet-efcore`, using that release's `barBuildId`: + +``` +darc update-dependencies --id +``` + +- `dotnet-efcore` commonly reports `warn: Found no dependencies to update` -- that is expected. +- .NET 9 is the coherent primary update: **keep everything darc changes**, including `eng/Version.Details.xml`, the non-suffixed `...Version` entries in `eng/Versions.props`, and the new `darc-int-*` feeds in `NuGet.config`. + +Review the changes, then stage and commit: + +``` +git add . +git commit -m "Update 9.0 dependencies" +``` + +## Sub-stage 2 - Update Dependencies: .NET 8 + +For each of `dotnet-runtime`, `dotnet-aspnetcore`, and `dotnet-efcore`, using the 8.0 release's `barBuildId`: + +``` +darc update-dependencies --id +``` + +`dotnet-efcore` commonly reports `warn: Found no dependencies to update`. + +Once all three repos are applied, fix up the changes so that only the 8.0 (`...LTSVersion`) entries move: + +1. Revert `Version.Details.xml` (the 8.0 update must not rewrite it): + + ``` + git checkout eng/Version.Details.xml + ``` + +2. `NuGet.config` -- resolve keeping both. Keep the pre-existing `darc-int-*` feeds (added by .NET 9) **and** the newly added 8.0 ones; discard the deletions and keep the additions. The result adds the new 8.0 `darc-int-*` sources: three in `` and three in ``. Then: + + ``` + git add NuGet.config + ``` + +3. `eng/Versions.props` hand-edit: + - Move the 8.0 versions darc produced into the matching `...LTSVersion` entries, replacing their previous values (that is, take the updated numbers from the non-suffixed `...Version` entries and write them into the corresponding `...LTSVersion` entries -- "Version>" becomes "LTSVersion>"). + - Revert the changes to the 9.0 (non-suffixed `...Version`) lines. + - Revert changes to entries that have no 8.0 update: `Microsoft.Bcl.Memory`, `System.Numerics.Tensors`, `System.Memory.Data`. + - Then `git add eng/Versions.props`. + +4. Commit: + + ``` + git commit -m "Update 8.0 dependencies" + ``` + +Only `NuGet.config` and `eng/Versions.props` belong in this commit. + +## Sub-stage 3 - Update Dependencies: .NET 10 + +Apply each 10.0 BAR build ID (order does not matter): + +``` +darc update-dependencies --id --no-coherency-updates +``` + +Once all IDs are applied, fix up the changes: + +1. Revert `Version.Details.xml`: + + ``` + git checkout eng/Version.Details.xml + ``` + +2. Revert the Arcade / Helix / Build.Tasks.Templating tooling file changes under `eng/common/` (darc rewrites these because Arcade ships in the VMR): + + ``` + git checkout eng/common + ``` + +3. `NuGet.config` -- resolve keeping both, exactly as in Sub-stage 2: keep the pre-existing and the newly added `darc-int-*` feeds. Then `git add NuGet.config`. + +4. `eng/Versions.props` hand-edit: + - **Keep** the Arcade `MicrosoftDotNetBuildTasksTemplating*Version` entry updates (both the base entry and the `...Net10Version` variant). These stay -- only the `eng/common/` tooling files and `Version.Details.xml` are reverted for Arcade. + - Move the 10.0 versions darc produced into the matching `...Net10Version` entries, replacing their previous values ("Version>" becomes "Net10Version>"). + - Revert the changes to the 9.0 (non-suffixed `...Version`) lines. + - Then `git add eng/Versions.props`. + +5. Commit: + + ``` + git commit -m "Update 10.0 dependencies" + ``` + +Only `NuGet.config` and `eng/Versions.props` belong in this commit -- no `eng/common/` files and no `Version.Details.xml`. + +## After the stage + +Do not push from within this stage. Pushing the `stage-release-.` branch is a separate, user-directed step. When it happens, resolve the internal remote by its URL (`dev.azure.com/dnceng/internal/_git/dotnet-extensions`) rather than assuming a remote name, which varies between clones. diff --git a/.github/skills/update-otel-genai-conventions/SKILL.md b/.github/skills/update-otel-genai-conventions/SKILL.md index 7b5d4f531b8..1faee1f342e 100644 --- a/.github/skills/update-otel-genai-conventions/SKILL.md +++ b/.github/skills/update-otel-genai-conventions/SKILL.md @@ -1,20 +1,130 @@ --- name: update-otel-genai-conventions description: >- - Analyze OpenTelemetry semantic-conventions releases or PRs with gen-ai changes - and produce compensating change plans for dotnet/extensions. Use when asked to - "update OTel conventions", "check semantic-conventions release", "plan gen-ai - convention changes", review gen-ai convention PRs, or when given a release - version, URL, or PR number/URL from open-telemetry/semantic-conventions with - area:gen-ai changes. Also use when asked to "update OpenTelemetry", "bump - semconv version", or "what changed in semantic-conventions vX.Y". + Analyze OpenTelemetry GenAI semantic-conventions changes (PRs, CHANGELOG + snapshots, date ranges, or releases when they exist) and produce + compensating change plans for dotnet/extensions. The conventions now live + in their own repo at open-telemetry/semantic-conventions-genai and cover + gen-ai, mcp, openai, anthropic, aws-bedrock, and azure-ai-inference areas; + the previous home was open-telemetry/semantic-conventions under the + area:gen-ai label. Use when asked to "update OTel conventions", "check + semantic-conventions-genai", "plan gen-ai convention changes", "bump genai + semconv version", review gen-ai/MCP/provider convention PRs, or when given + a PR number/URL, CHANGELOG snapshot, date range, or release version from + either repo. Also use for "update OpenTelemetry", "bump semconv version", + or "what changed in semantic-conventions-genai". agent: 'agent' tools: ['github/*', 'sql'] --- # Update OTel Gen-AI Conventions -Analyze OpenTelemetry [semantic-conventions](https://github.com/open-telemetry/semantic-conventions) releases or PRs with `area:gen-ai` changes and produce compensating updates in `dotnet/extensions`. +Analyze OpenTelemetry GenAI semantic-conventions changes — PRs, changelog snapshots, date ranges, or releases — primarily from [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai), and produce compensating updates in `dotnet/extensions`. See the [Migration Note](#migration-note) below for context, including where these conventions were previously managed. + +## Migration Note + +The OpenTelemetry GenAI semantic conventions are maintained in a dedicated +repo: +[`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai), +which also hosts `mcp`, `openai`, `anthropic`, `aws-bedrock`, and +`azure-ai-inference` conventions. They were previously managed in the +consolidated +[`open-telemetry/semantic-conventions`](https://github.com/open-telemetry/semantic-conventions) +repo under the `area:gen-ai` label. + +Implications for this skill: + +- **Primary input source** is `semantic-conventions-genai`. The + consolidated `semantic-conventions` repo remains a **fallback** for + catch-up audits, historical context, and any in-flight PR that started + there previously. +- **Every PR is in scope for consideration**, because + `semantic-conventions-genai` is specific to GenAI conventions. (In the + consolidated `semantic-conventions` repo the `area:gen-ai` label scoped + this work, and it still applies there for catch-up.) The repo does use + more granular `area:*` labels (for example `area:mcp`, `area:inference`, + `area:tools`, `area:embeddings`), which can help triage but are not + required for scoping. +- **No releases yet** in `semantic-conventions-genai`. + + The repo manages its changelog with **Towncrier**: the `CHANGELOG.md` + `Unreleased` section is intentionally empty (fragments are compiled into + it only at release time), so the live "what's new" view is the set of + news fragments under `changelog.d/`, each named `..md` + (types include `enhancement`, `bugfix`, `breaking`, `clarification`). Pin + a snapshot via commit SHA / ref for reproducible audits. +- **GenAI version is now independent** of core semconv: it tracks its own + version line. The schema URL + `https://opentelemetry.io/schemas/gen-ai/X.Y.Z` is intended to carry the + gen-ai version, but is **not published yet** (the repo's `README.md` + `## Schema URL` section is `TODO`). The repo's `versions.env` holds + only the **core semconv dependency** (`SEMCONV_VERSION`, currently + `v1.42.0`) and the Weaver toolchain version — it does **not** carry the + GenAI convention version, so do not treat `SEMCONV_VERSION` as the GenAI + version. Until a GenAI release or schema URL exists, there is no + published GenAI version number; identify the update by its `changelog.d/` + fragment snapshot, pinned to a commit SHA / ref / date. +- **Spec URL `https://opentelemetry.io/docs/specs/semconv/gen-ai/` + currently resolves to a "Moved" stub** that states the GenAI + conventions have moved to `semantic-conventions-genai` and is no longer + maintained; it no longer renders the spec content. The `` in + dotnet/extensions source files still points at this URL, so leave it for + now but revisit retargeting it once OpenTelemetry publishes a canonical + URL for the conventions (the repo's `README.md` `## Schema URL` section + is currently `TODO`). + +- **PR numbering** is not interchangeable across repos. Always + disambiguate with `open-telemetry/semantic-conventions#NNN` or + `open-telemetry/semantic-conventions-genai#NNN` when there is any risk + of collision. +- **Doc-comment wording** in dotnet/extensions source still reads + "Semantic Conventions for Generative AI systems v1.XX". The next + convention-update PR should migrate this to "GenAI Semantic Conventions + vX.Y.Z" — see [references/file-inventory.md §Version References](references/file-inventory.md#version-references). + +When a referenced PR number doesn't resolve in `semantic-conventions-genai`, +check the consolidated `semantic-conventions` repo before assuming the +input is invalid. + +## Cross-repo applicability + +This skill lives in `dotnet/extensions` and its file paths, build +commands, and PR-description conventions are tuned for that repo. The +`semantic-conventions-genai` repo also hosts provider-specific areas +(`anthropic`, `aws-bedrock`) whose dotnet instrumentation lives in +**other** SDK repositories that we contribute to: + +| Upstream area | Repository | Notes | +|---|---|---| +| `anthropic` | [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) | Anthropic's official .NET SDK. | +| `aws-bedrock` | [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net) | AWS Bedrock instrumentation lives in the `BedrockRuntime` service library (`AWSSDK.BedrockRuntime`) inside the AWS SDK monorepo. | + +The skill can optionally be applied in those repos with the following +adaptations: + +- **Apply** the convention analysis, classification framework + ([references/change-classification.md](references/change-classification.md)), + audit-table shape, area routing, doc-comment wording target + ("GenAI Semantic Conventions vX.Y.Z"), version-reference grep + recipes, and PR-description shape + ([references/pr-description.md](references/pr-description.md)). +- **Do not assume** dotnet/extensions-specific paths + (`src/Libraries/Microsoft.Extensions.AI*/`), the + `OpenTelemetryConsts.cs` constants layout, the API-baseline workflow, + or the build/test commands in + [references/build-commands.md](references/build-commands.md). Use the + target repo's own conventions for code structure, constants + organization, and validation. +- **Scope by repo**: when running in another repo, the in-scope upstream + area is the one that repo instruments (e.g. `anthropic` in + `anthropics/anthropic-sdk-csharp`, `aws-bedrock` in the + `BedrockRuntime` library of `aws/aws-sdk-net`). Other areas are out + of scope from that repo's perspective even though they remain in + scope for `dotnet/extensions`. +- **Pre-flight** still applies — search open PRs in the target repo for + prior coverage before producing a plan. ## Mode Detection @@ -33,21 +143,72 @@ If unclear, default to **Mode 5** (Plan-then-Implement) and offer Mode 3 as an a ## Input Handling -The user provides one of: -- A **semantic-conventions release version** (e.g. `v1.40.0`) → fetch from `https://github.com/open-telemetry/semantic-conventions/releases/tag/{version}` -- A **release URL** → fetch the release notes directly -- One or more **PR references** from `open-telemetry/semantic-conventions` with `area:gen-ai` changes — as URLs, PR numbers (e.g. `#3598`), or `open-telemetry/semantic-conventions#3598` format - -When PR numbers are given without a full URL, resolve them against the `open-telemetry/semantic-conventions` repository. +`semantic-conventions-genai` does not yet publish releases. Until it does, +the user typically provides one of: + +- **PR references** in `semantic-conventions-genai` — full URL, `#NNN`, or + `open-telemetry/semantic-conventions-genai#NNN` form. (No `area:` label + filter is needed: the repo is gen-ai-focused by definition.) +- **A `changelog.d/` snapshot** — a commit SHA, branch ref, or a + `https://github.com/open-telemetry/semantic-conventions-genai/tree/{ref}/changelog.d` + URL pinning the Towncrier news fragments at a point in time. (The + `CHANGELOG.md` `Unreleased` section stays empty until release, so use the + fragments — not `CHANGELOG.md` — for unreleased work.) +- **A date range or "since last update"** — list of PRs merged to + `semantic-conventions-genai`'s `main` between two refs / dates. +- **A release version or release URL** — once releases exist + (`https://github.com/open-telemetry/semantic-conventions-genai/releases/tag/{version}`). + +For **catch-up or historical work**, the consolidated +`semantic-conventions` repo is still valid input: + +- A **semantic-conventions release version** (e.g. `v1.40.0`) → fetch from + `https://github.com/open-telemetry/semantic-conventions/releases/tag/{version}` + (filter to `area:gen-ai` PRs). +- A **release URL** from `semantic-conventions` → fetch the release notes directly. +- **PR references** from `semantic-conventions` — only the ones with `area:gen-ai`. + Use the `open-telemetry/semantic-conventions#NNN` form to disambiguate + from `semantic-conventions-genai` PR numbers. + +When PR numbers are given without a full URL, default to +`semantic-conventions-genai` and fall back to the consolidated +`semantic-conventions` repo only if the PR doesn't exist in +`semantic-conventions-genai` or the user explicitly references it. + +### In-scope areas + +The `semantic-conventions-genai` repo hosts conventions for several areas, all of which this skill +covers (with placement guidance in +[references/implementation-patterns.md](references/implementation-patterns.md)): + +| Upstream area | Maps to in dotnet/extensions | +|---|---| +| `gen-ai`, `gen-ai/agent` | `Microsoft.Extensions.AI` core (e.g. `OpenTelemetryChatClient`) | +| `mcp` | Currently no instrumentation; forward-looking — flag as a watch-list item if changes appear | +| `openai` | `Microsoft.Extensions.AI.OpenAI` | +| `anthropic` | Out of scope for `dotnet/extensions` today (no provider package). Implications land in [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) — apply this skill there per [Cross-repo applicability](#cross-repo-applicability). | +| `aws-bedrock` | Out of scope for `dotnet/extensions` today (no provider package). Implications land in the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net) — apply this skill there per [Cross-repo applicability](#cross-repo-applicability). | +| `azure-ai-inference` | Corresponding provider package, if/when one exists in this repo; otherwise out of scope | + +When classifying a change, identify its area as follows. `gen-ai`, +`mcp`, `openai`, and `aws-bedrock` each have a YAML registry under +`model//`, so use that path. `anthropic` and `azure-ai-inference` +do **not** have a `model/` registry today; they are documented only as +provider pages under `docs/gen-ai/.md`. All human-readable +docs live under `docs/gen-ai/` (for example `docs/gen-ai/openai.md`, +`docs/gen-ai/mcp.md`, `docs/gen-ai/anthropic.md`), not under +`docs//`. ### Existing dotnet/extensions PR Preflight -For **Mode 1: Audit** and **Mode 5: Plan-then-Implement**, after resolving the requested release or upstream PR identifiers but before doing deeper release analysis or creating a plan, search open pull requests in `dotnet/extensions` to determine whether another PR already appears to cover the requested GenAI/OpenTelemetry semantic-conventions update. +For **Mode 1: Audit** and **Mode 5: Plan-then-Implement**, after resolving the requested input identifiers but before doing deeper analysis or creating a plan, search open pull requests in `dotnet/extensions` to determine whether another PR already appears to cover the requested update. -Search using the requested release version, release URL, or upstream semantic-conventions PR numbers, plus relevant terms such as `gen-ai`, `GenAI`, `semantic conventions`, `OpenTelemetry`, and `OTel`. If one or more likely matching PRs are open, report the PR number, title, author, URL, and the signal that matched. Then stop and state that the audit or plan is not proceeding because an open PR already appears to cover the update. +Search using the requested release version, CHANGELOG ref, date range, or upstream PR numbers, plus relevant terms such as `gen-ai`, `GenAI`, `semantic conventions`, `semantic-conventions-genai`, `semconv-genai`, `OpenTelemetry`, `OTel`, and any in-scope area name (`MCP`, `OpenAI`, `Anthropic`, `Bedrock`, `Azure AI Inference`) that matches the changes you're working from. If one or more likely matching PRs are open, report the PR number, title, author, URL, and the signal that matched. Then stop and state that the audit or plan is not proceeding because an open PR already appears to cover the update. Do not silently ignore search failures. If GitHub search/listing is unavailable, report the problem and ask the user whether to proceed without the preflight. +A standing **upstream-scan tracking PR** (one carrying the `otel-genai-tracking` state block) is the exception: it is the durable scan record, not a blocking duplicate. When the preflight surfaces it, refresh it per **Refreshing the tracking PR** in [references/pr-description.md](references/pr-description.md#refreshing-the-tracking-pr) instead of stopping. + ### Analyzing the Release / PRs 1. **Fetch the release notes** or PR descriptions and identify all gen-ai changes @@ -60,7 +221,7 @@ For Step 4, read the source files listed in [references/file-inventory.md](refer ### PR Title and Description Guidance -When creating or updating a PR after implementing semantic-conventions changes, follow [references/pr-description.md](references/pr-description.md) for the title format and the changes-table shape. +When creating or updating a PR after implementing GenAI semantic-conventions changes (from either repo), follow [references/pr-description.md](references/pr-description.md) for the title format and the changes-table shape. For a recurring **upstream-scan tracking PR** (the kind carrying the `otel-genai-tracking` state block), that reference also defines the full body template -- the implemented-changes table, the merged and in-flight applicability tables, and, at the very bottom, the machine-readable tracking state block (the body ends there). The refresh procedure for that PR lives in the skill itself, not in the PR body. --- @@ -71,7 +232,8 @@ Audit the current gen-ai semantic conventions implementation against the latest 1. Complete the **Existing dotnet/extensions PR Preflight** above. If a matching open PR exists, report it and stop. 2. **Determine the current implemented version**: Read the version reference from `OpenTelemetryChatClient.cs` doc comment to identify which convention version the codebase claims to implement 3. **Check for version drift**: Verify every file with a gen-ai semantic conventions version reference uses the same version. Use the search command from [references/file-inventory.md](references/file-inventory.md#version-references). If files reference different versions, flag that as a critical gap requiring investigation. -4. **Fetch the latest convention spec**: Read the current gen-ai semantic conventions from the [published spec](https://opentelemetry.io/docs/specs/semconv/gen-ai/) and the latest release notes +4. **Fetch the latest convention spec**: Read the current conventions from the source of truth in [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai): `docs/gen-ai/` for human-readable docs (for example `docs/gen-ai/gen-ai-spans.md`, `docs/gen-ai/openai.md`) and `model//` for the YAML registry (`gen-ai`, `mcp`, `openai`, `aws-bedrock`). Note the published page at `https://opentelemetry.io/docs/specs/semconv/gen-ai/` is currently a "Moved" stub and no longer renders the spec. There is no `schema-snapshot/` directory, and the schema URL (`opentelemetry.io/schemas/gen-ai/X.Y.Z`) is not published yet (the repo `README.md` `## Schema URL` section is `TODO`). The repo's `versions.env` holds only the core semconv dependency (`SEMCONV_VERSION`) and the Weaver version — not a GenAI version — so do not treat `SEMCONV_VERSION` as the GenAI version. Until a GenAI release or schema URL exists, there is no published GenAI version number; identify the update by its `changelog.d/` fragment snapshot (commit SHA / ref / date). The GenAI convention version is independent of core semconv. Until releases exist in `semantic-conventions-genai`, use the latest `changelog.d/` news fragments or recently merged PRs as the "latest release notes" equivalent. + 5. **Read all current source files** listed in [references/file-inventory.md](references/file-inventory.md) to understand what is actually implemented 6. **Cross-reference**: For each attribute, metric, event, and operation name defined in the conventions: - Is the constant defined in `OpenTelemetryConsts.cs`? @@ -101,7 +263,7 @@ Modes 2, 4, and 5 share the same implementation flow. See [references/implementa ## Mode 2: Autopilot -One-shot mode that analyzes the release and implements all changes in a single pass without intermediate review. Best for end-to-end execution when the user does not need a plan checkpoint. +One-shot mode that analyzes the upstream input (release, PRs, CHANGELOG snapshot, or date range) and implements all changes in a single pass without intermediate review. Best for end-to-end execution when the user does not need a plan checkpoint. 1. Complete the **Input Handling** analysis above 2. Build an internal work plan in working memory (do not write `plan.md`): @@ -119,8 +281,8 @@ Generate a structured prompt suitable for delegating to Copilot Coding Agent on 1. Complete the **Input Handling** analysis above 2. Read [references/prompt-template.md](references/prompt-template.md) for the template structure 3. Generate the prompt following the template, filling in: - - Background with links to the upstream release/PRs - - Changes audit table + - Background with links to the upstream input (release URL, CHANGELOG snapshot ref, date range, or PR URLs) + - Changes audit table (with **Area** column) - Required changes with exact file paths and code context from the current source - Test expectations referencing [references/testing-guide.md](references/testing-guide.md) - Validation steps @@ -146,10 +308,10 @@ Generate a plan and (after user review/approval) implement it. Best when the use **Phase A: Plan** — -1. Resolve the user's input to a semantic-conventions release or upstream PR identifiers +1. Resolve the user's input to one of: a release, PR identifiers, a `changelog.d/` fragment snapshot (commit SHA / ref), or a date range in `semantic-conventions-genai` (`open-telemetry/semantic-conventions-genai`). For catch-up work, accept upstream PRs from the consolidated `open-telemetry/semantic-conventions` repo with `area:gen-ai` 2. Complete the **Existing dotnet/extensions PR Preflight** above. If a matching open PR exists, report it and stop without creating a plan. 3. Complete the **Analyzing the Release / PRs** analysis above -4. Create `plan.md` with a problem statement linking to the upstream release, a changes audit table, and a numbered list of work items. Each work item should call out the file(s) to modify, what code/constants/attributes to add, and which tests to update. +4. Create `plan.md` with a problem statement linking to the upstream input (release URL, CHANGELOG snapshot ref, date range, or list of PR URLs — whichever applies), a changes audit table, and a numbered list of work items. Each work item should call out the file(s) to modify, what code/constants/attributes to add, and which tests to update. 5. Pause for user review/approval before proceeding to Phase B **Phase B: Implement** — @@ -187,11 +349,12 @@ Critical knowledge from past PR reviews that should inform all modes: - **Fluent chains**: Use fluent Activity API chains (`.SetStatus(...).SetTag(...)`) rather than separate statements. - **Shared code**: Cross-cutting concerns (like exception logging) shared across multiple OpenTelemetry* clients belong in `src/Libraries/Microsoft.Extensions.AI/Common/`. Before adding a new helper, method, or internal type, search `Common/`, `TelemetryHelpers.cs`, `OpenTelemetryLog.cs`, and sibling OpenTelemetry* clients for existing logic with the same purpose — reuse or extend instead of introducing a parallel implementation. When the same helper is needed in 2+ places, factor it into `Common/` from the start. The same applies to parallel internal types: if a sibling client already defines a type with the same shape (same properties, same role, e.g. `RealtimeOtelFunction` vs `OtelFunction`), unify them under a single shared definition rather than letting each client carry its own copy. - **Test augmentation**: Prefer augmenting existing test assertions over creating new test methods. Check for existing tests that validate the same scenario. -- **Version references**: When bumping the convention version, update all files that match `grep -rn "Semantic Conventions for Generative AI systems v" src/Libraries/Microsoft.Extensions.AI/`. Not all OpenTelemetry* files contain this reference — only update the ones that do. +- **Version references**: When bumping the convention version, update all files that match the transitional regex `grep -rEn "Semantic Conventions for Generative AI systems v|GenAI Semantic Conventions v" src/Libraries/Microsoft.Extensions.AI/` (handles both pre- and post-migration wording). The next convention update should also migrate the wording in lockstep — see [references/file-inventory.md §Version References](references/file-inventory.md#version-references). Not all OpenTelemetry* files contain this reference — only update the ones that do. - **No CHANGELOGs**: This repository no longer maintains per-library CHANGELOG.md files. Do NOT create or update any CHANGELOG files. - **Source-generated JSON**: Adding new OTel part types requires: (1) new inner class, (2) `[JsonSerializable]` registration on `OtelContext`, (3) switch case in `SerializeChatMessages()`. - **LoggerMessage text**: When using `[LoggerMessage]`, the message text should match the OTel event name for console logger readability. - **No orphan constants**: Never add a constant to `OpenTelemetryConsts.cs` unless the same PR also adds at least one emission site for it. If the convention defines an attribute that no current client populates, classify the change as 🟢 *Constant not yet emitted* and defer the constant — do not add it ahead of emission. Verify with `grep -rn NewConstantName src/Libraries/Microsoft.Extensions.AI/` before submitting. +- **Area-aware constants**: Pick the nested class in `OpenTelemetryConsts.cs` based on the upstream area: `GenAI.*` for `gen-ai/*`, `MCP.*` for `mcp/*`. Provider-specific attributes (`openai.*`, `anthropic.*`, `aws-bedrock.*`, `azure-ai-inference.*`) generally belong in the **provider package's** constants file, not in `Microsoft.Extensions.AI/OpenTelemetryConsts.cs`. See [references/implementation-patterns.md §Area placement guidance](references/implementation-patterns.md#area-placement-guidance). ## Validation diff --git a/.github/skills/update-otel-genai-conventions/references/change-classification.md b/.github/skills/update-otel-genai-conventions/references/change-classification.md index 40ef2264651..d5bd2191838 100644 --- a/.github/skills/update-otel-genai-conventions/references/change-classification.md +++ b/.github/skills/update-otel-genai-conventions/references/change-classification.md @@ -1,6 +1,21 @@ # Change Classification -Taxonomy for classifying gen-ai changes from semantic-conventions releases. Use this to assess each change's impact on dotnet/extensions. +Taxonomy for classifying GenAI semantic-conventions changes from PRs, CHANGELOG snapshots, date ranges, or releases (when they exist) in [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai). `area:gen-ai` PRs from the consolidated `semantic-conventions` repo (where these conventions were previously managed) classify the same way. Use this to assess each change's impact on dotnet/extensions. + +## Areas + +The `semantic-conventions-genai` repo hosts conventions for several areas. Identify the **area** of each change from its path: `gen-ai`, `mcp`, `openai`, and `aws-bedrock` have a YAML registry under `model//`; `anthropic` and `azure-ai-inference` have no `model/` registry today and exist only as provider doc pages under `docs/gen-ai/.md`. All human-readable docs live under `docs/gen-ai/`, not `docs//`: + +| Area | dotnet/extensions location | +|---|---| +| `gen-ai`, `gen-ai/agent` | `Microsoft.Extensions.AI` core (e.g. `OpenTelemetryChatClient`) | +| `mcp` | No instrumentation today — classify all `mcp` changes as 🟢 *No client exists* unless and until an MCP client is added | +| `openai` | `Microsoft.Extensions.AI.OpenAI` (provider package) | +| `anthropic` | Out of scope for `dotnet/extensions` (no provider package). Classify as 🟢 *No client exists* **from the perspective of this repo**. The compensating change actually lands in [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) — see [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `aws-bedrock` | Out of scope for `dotnet/extensions` (no provider package). Classify as 🟢 *No client exists* **from the perspective of this repo**. The compensating change actually lands in the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net) — see [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `azure-ai-inference` | Corresponding provider package if/when one exists in this repo; otherwise classify as 🟢 *No client exists* | + +When the area is provider-specific (`openai`, `anthropic`, `aws-bedrock`, `azure-ai-inference`), the compensating change usually belongs in the corresponding provider package, **not** in `Microsoft.Extensions.AI`. For `anthropic` ([`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp)) and `aws-bedrock` (the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net)) this provider package lives in another SDK repo entirely; when running this skill in `dotnet/extensions`, audit-flag the change but classify it as out-of-scope and link the upstream change so a follow-up can be opened in the right SDK repo. When running this skill **in** that SDK repo, treat the area as in-scope and route the change to that repo's own constants/instrumentation files. ## Classification Categories @@ -63,28 +78,32 @@ For each gen-ai change in a release: ## Audit Table Format -When presenting the analysis, use this table format: +When presenting the analysis, use this table format. The **Area** column lets reviewers see at a glance which dotnet/extensions package each change targets: ```markdown -| Semantic Convention Change | Upstream PR | Classification | Action Required | Complexity | -|---|---|---|---|---| -| `gen_ai.new.attribute` | [#1234](link) | New required attribute | Add constant + emission + test | Low | -| `gen_ai.deferred.attribute` | [#2345](link) | Constant not yet emitted | Defer — no client populates this attribute in this PR | — | -| `retrieval` operation | [#5678](link) | N/A — No client | None | — | -| Version reference | — | Version bump | Update doc comments | Low | +| Area | Semantic Convention Change | Upstream PR | Classification | Action Required | Complexity | +|---|---|---|---|---|---| +| `gen-ai` | `gen_ai.new.attribute` | [open-telemetry/semantic-conventions-genai#1234](link) | New required attribute | Add constant + emission + test in `Microsoft.Extensions.AI` | Low | +| `gen-ai` | `gen_ai.deferred.attribute` | [open-telemetry/semantic-conventions-genai#2345](link) | Constant not yet emitted | Defer — no client populates this attribute in this PR | — | +| `mcp` | `mcp.tool.approval` | [open-telemetry/semantic-conventions-genai#3456](link) | N/A — No client | None — no MCP instrumentation today | — | +| `openai` | `openai.new.attribute` | [open-telemetry/semantic-conventions-genai#4567](link) | New required attribute | Add to `Microsoft.Extensions.AI.OpenAI` provider package | Low | +| `anthropic` | `anthropic.new.attribute` | [open-telemetry/semantic-conventions-genai#5678](link) | N/A — No client (in this repo) | Out of scope here — [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) is the actual target. Open a follow-up there. | — | +| `gen-ai` | Version reference | — | Version bump | Update doc comments to new wording | Low | ``` ## PR Description Table Format -When preparing a PR description, adapt the audit table into a concise reviewer-facing table grouped or sorted by semantic-conventions version. Include every analyzed gen-ai change, not just changes that required code edits. +When preparing a PR description, adapt the audit table into a concise reviewer-facing table grouped or sorted by GenAI version (the version from the schema URL or CHANGELOG release header — independent of core semconv). Include every analyzed change, not just changes that required code edits. ```markdown -| Version | Indicator | Semantic-conventions change | Classification | Compensating change / rationale | -|---|:---:|---|---|---| -| v1.XX | 🔴 | `gen_ai.new.attribute` added | New required attribute | Added constant, emission, and tests in `{files}`. | -| v1.XX | 🟡 | Version reference update | Version bump | Updated OpenTelemetry* doc comments to v1.XX. | -| v1.XX | 🟢 | Provider server span clarified | Server-side only | No client-side instrumentation change needed. | -| v1.XX | 🟢 | `gen_ai.deferred.attribute` added upstream | Constant not yet emitted | No client populates this attribute today; constant will be added in the PR that adds emission. | +| Version | Area | Indicator | Semantic-conventions change | Classification | Compensating change / rationale | +|---|---|:---:|---|---|---| +| vX.Y.Z | `gen-ai` | 🔴 | `gen_ai.new.attribute` added | New required attribute | Added constant, emission, and tests in `{files}`. | +| vX.Y.Z | `gen-ai` | 🟡 | Version reference update | Version bump | Updated OpenTelemetry* doc comments to the new wording. | +| vX.Y.Z | `gen-ai` | 🟢 | Provider server span clarified | Server-side only | No client-side instrumentation change needed. | +| vX.Y.Z | `gen-ai` | 🟢 | `gen_ai.deferred.attribute` added upstream | Constant not yet emitted | No client populates this attribute today; constant will be added in the PR that adds emission. | +| vX.Y.Z | `openai` | 🔴 | `openai.new.attribute` added | New required attribute | Added to `Microsoft.Extensions.AI.OpenAI` provider package. | +| vX.Y.Z | `mcp` | 🟢 | `mcp.tool.approval` added | N/A — No client | No MCP instrumentation in this repo today. | ``` -The final column should either describe the compensating change made or explain why no code change was made, such as "already implemented", "no local source exists", "no client exists", "server-side only", "documentation-only clarification", or "no client populates this attribute today; constant deferred until a PR adds emission". +The final column should either describe the compensating change made or explain why no code change was made, such as "already implemented", "no local source exists", "no client exists", "server-side only", "documentation-only clarification", "no client populates this attribute today; constant deferred until a PR adds emission", "provider-specific area not instrumented in this repo", or "out of scope here — implications land in `anthropics/anthropic-sdk-csharp` (anthropic) or the `BedrockRuntime` library of `aws/aws-sdk-net` (aws-bedrock); follow-up opened in that repo". diff --git a/.github/skills/update-otel-genai-conventions/references/file-inventory.md b/.github/skills/update-otel-genai-conventions/references/file-inventory.md index b1d9aa977cc..947bdabee8c 100644 --- a/.github/skills/update-otel-genai-conventions/references/file-inventory.md +++ b/.github/skills/update-otel-genai-conventions/references/file-inventory.md @@ -60,14 +60,61 @@ To discover any additional test files: `dir test\Libraries\Microsoft.Extensions. The semantic conventions version is referenced in a doc comment in specific OpenTelemetry* instrumentation client files. When bumping the version, update all files that match the grep below — not all OpenTelemetry* files contain the version reference. -The reference looks like: +### Current wording (pre-migration) + +The reference today still reads (carried over from when conventions lived in the core `open-telemetry/semantic-conventions` repo): ```csharp /// This class provides an implementation of the Semantic Conventions for Generative AI systems v1.XX, /// defined at . ``` -Find all occurrences with: +### Target wording (post-migration) + +After the GenAI conventions moved to [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai), the doc comment should call out the standalone repo and use a GenAI-namespaced version (`vX.Y.Z`). Until `semantic-conventions-genai` publishes a release or schema URL, take that version from the `changelog.d/` fragment snapshot you audited — not from `versions.env` (whose `SEMCONV_VERSION` is the core semconv dependency, not the GenAI version): + +```csharp +/// This class provides an implementation of the GenAI Semantic Conventions vX.Y.Z, +/// defined at . +``` + +The `` URL is kept for now: the published page at `https://opentelemetry.io/docs/specs/semconv/gen-ai/` currently resolves only to a "Moved" stub that points at `semantic-conventions-genai` and no longer renders the spec. Leave the URL in place until OpenTelemetry publishes a canonical URL for the conventions (the `semantic-conventions-genai` `README.md` `## Schema URL` section is `TODO`), then retarget it. Do not use that page as the spec source — read `docs/gen-ai/` and `model//` in `semantic-conventions-genai` instead. + +### Wording migration + +This wording change is a **one-time edit** that should ride along with the +**next convention-update PR** (not a separate cosmetic PR). Until that +update lands, both wordings may coexist transiently in the codebase. + +### Finding occurrences during the transition + +Use a regex that matches both wordings: + +```bash +grep -rEn "Semantic Conventions for Generative AI systems v|GenAI Semantic Conventions v" src/Libraries/Microsoft.Extensions.AI/ ``` -grep -rn "Semantic Conventions for Generative AI systems v" src/Libraries/Microsoft.Extensions.AI/ + +Once every file has been migrated to the target wording, the regex can be +simplified back to a single literal: + +```bash +grep -rn "GenAI Semantic Conventions v" src/Libraries/Microsoft.Extensions.AI/ ``` + +## Provider-specific instrumentation + +The new conventions repo also covers provider-specific areas (`openai`, +`anthropic`, `aws-bedrock`, `azure-ai-inference`). Provider-specific +attributes like `openai.*` belong in the **provider package**, not in +`Microsoft.Extensions.AI`: + +| Upstream area | dotnet/extensions location | +|---|---| +| `openai` | `src/Libraries/Microsoft.Extensions.AI.OpenAI/` (e.g. `OpenAIClientExtensions.cs` for `openai.api.type` mapping) | +| `anthropic` | Out of scope for `dotnet/extensions` today — implications land in [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp). See [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `aws-bedrock` | Out of scope for `dotnet/extensions` today — implications land in the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net). See [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `azure-ai-inference` | Corresponding provider package, if/when one exists in this repo; otherwise out of scope | +| `mcp` | No instrumentation today — flag as a watch-list item if MCP changes appear | + +Tests for provider-specific attributes live alongside the provider package +(e.g. `test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/`). diff --git a/.github/skills/update-otel-genai-conventions/references/historical-releases.md b/.github/skills/update-otel-genai-conventions/references/historical-releases.md index e6ed6af9c3e..a97f5e4496c 100644 --- a/.github/skills/update-otel-genai-conventions/references/historical-releases.md +++ b/.github/skills/update-otel-genai-conventions/references/historical-releases.md @@ -1,8 +1,15 @@ # Historical Releases -Mapping of OpenTelemetry semantic-conventions releases with gen-ai changes to dotnet/extensions PRs. +Mapping of OpenTelemetry GenAI semantic-conventions releases to dotnet/extensions PRs. -> **Note**: This file is a point-in-time reference and is not intended to be kept up to date with every new release. It provides context for how past convention updates were handled. For the latest release history, consult the [semantic-conventions releases page](https://github.com/open-telemetry/semantic-conventions/releases) and search the dotnet/extensions PR history. +> **Migration Note**: Every entry in the tables below is from the consolidated [`open-telemetry/semantic-conventions`](https://github.com/open-telemetry/semantic-conventions) repo, where GenAI conventions were previously managed and tagged with `area:gen-ai`. GenAI conventions are now maintained in a dedicated repo: [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai). See [SKILL.md §Migration Note](../SKILL.md#migration-note) for the full picture. +> +> **Point-in-time reference**: This file is not intended to be kept up to date with every new release. It provides context for how past convention updates were handled. For current activity, consult: +> +> - The [`semantic-conventions-genai` `changelog.d/` fragments](https://github.com/open-telemetry/semantic-conventions-genai/tree/main/changelog.d) (Towncrier news fragments are the live "what's new" view until releases land; the `CHANGELOG.md` `Unreleased` section stays empty until release). +> - The [`semantic-conventions-genai` releases page](https://github.com/open-telemetry/semantic-conventions-genai/releases) (empty as of this writing). +> - The [`semantic-conventions-genai` pull request history](https://github.com/open-telemetry/semantic-conventions-genai/pulls?q=is%3Apr). +> - The dotnet/extensions PR history. ## Release History diff --git a/.github/skills/update-otel-genai-conventions/references/implementation-patterns.md b/.github/skills/update-otel-genai-conventions/references/implementation-patterns.md index 3a9f0af7f75..1ee5e4463fb 100644 --- a/.github/skills/update-otel-genai-conventions/references/implementation-patterns.md +++ b/.github/skills/update-otel-genai-conventions/references/implementation-patterns.md @@ -4,6 +4,19 @@ Code patterns for common convention update change types. Use these as templates > **Reuse before adding.** Before applying any of the patterns below, search the touched libraries (`Common/`, `TelemetryHelpers.cs`, `OpenTelemetryLog.cs`, and sibling OpenTelemetry* client files) for an existing helper, method, or internal type that already does the same thing. Reuse or extend it instead of adding a parallel implementation. If the same logic will be needed in two or more places, factor it into `Common/` from the start rather than duplicating it per file. The same rule applies to parallel internal types — when a sibling client already defines a type with the same shape, unify under a single shared definition. See [review-checklist.md §3](review-checklist.md#3-code-deduplication) for what reviewers look for. +## Area placement guidance + +The new conventions repo ([`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai)) hosts multiple areas. Pick the right dotnet/extensions location based on the upstream area of the change — its `model//` registry path for `gen-ai`, `mcp`, `openai`, and `aws-bedrock`, or its `docs/gen-ai/.md` page for `anthropic` and `azure-ai-inference` (which have no `model/` registry today): + +| Upstream area | dotnet/extensions location | Notes | +|---|---|---| +| `gen-ai`, `gen-ai/agent` | `src/Libraries/Microsoft.Extensions.AI/` (e.g. `OpenTelemetryChatClient.cs`, `OpenTelemetryConsts.cs` under `GenAI.*`) | Generic gen-ai instrumentation — the bulk of historical work. | +| `mcp` | No instrumentation today — forward-looking | If MCP changes appear, classify as 🟢 *No client exists* and flag for follow-up. Do not add `MCP.*` constants speculatively. | +| `openai` | `src/Libraries/Microsoft.Extensions.AI.OpenAI/` (e.g. `OpenAIClientExtensions.cs` for `openai.api.type` mapping). Tests in `test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/`. | Keep `OpenTelemetryChatClient` provider-agnostic; provider-specific attributes belong in the provider package. | +| `anthropic` | Out of scope for `dotnet/extensions` today. Implications land in [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp). | If you're using this skill in that repo, follow the target repo's own constants/file layout. See [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `aws-bedrock` | Out of scope for `dotnet/extensions` today. Implications land in the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net). | If you're using this skill in that repo, follow the target repo's own constants/file layout. See [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability). | +| `azure-ai-inference` | Corresponding provider package, if/when one exists in this repo | Currently no provider package for this in this repo — classify as 🟢 *No client exists* until one is added. | + ## Pattern 1: Adding a New Constant Location: `src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs` @@ -129,18 +142,32 @@ if (_logger is not null) ## Pattern 6: Updating Version References -When bumping the convention version (e.g. v1.39 → v1.40), update the doc comment in all matched OpenTelemetry* client files: +When bumping the convention version (e.g. an upcoming GenAI version bump), update the doc comment in all matched OpenTelemetry* client files. The wording is in the middle of a one-time migration to reflect the standalone GenAI repo — see [file-inventory.md §Version References](file-inventory.md#version-references) for full guidance. + +**Pre-migration wording** (carried over from when conventions lived in core `semantic-conventions`): ```csharp -// Before: /// Semantic Conventions for Generative AI systems v1.39, -// After: -/// Semantic Conventions for Generative AI systems v1.40, ``` -Find all occurrences: +**Target wording** (after migration to the standalone repo, using a GenAI-namespaced version `vX.Y.Z` taken from the `changelog.d/` fragment snapshot you audited — not from `versions.env`'s `SEMCONV_VERSION`, which is the core semconv dependency): + +```csharp +/// GenAI Semantic Conventions vX.Y.Z, +``` + +The next convention-update PR should migrate every matched file from the pre-migration wording to the target wording in one shot. Do not leave files in a half-migrated state. + +Find all occurrences using a regex that matches both wordings during the transition: + +```bash +grep -rEn "Semantic Conventions for Generative AI systems v|GenAI Semantic Conventions v" src/Libraries/Microsoft.Extensions.AI/ +``` + +After the migration is complete, simplify to: + ```bash -grep -rn "Semantic Conventions for Generative AI systems v" src/Libraries/Microsoft.Extensions.AI/ +grep -rn "GenAI Semantic Conventions v" src/Libraries/Microsoft.Extensions.AI/ ``` ## Pattern 7: Modifying Message Serialization diff --git a/.github/skills/update-otel-genai-conventions/references/implementation-procedure.md b/.github/skills/update-otel-genai-conventions/references/implementation-procedure.md index 64ea28cb071..25165f4a14a 100644 --- a/.github/skills/update-otel-genai-conventions/references/implementation-procedure.md +++ b/.github/skills/update-otel-genai-conventions/references/implementation-procedure.md @@ -6,9 +6,13 @@ Used by Modes 2 (Autopilot), 4 (CCA Implementation), and 5 (Plan-then-Implement) 2. Read [review-checklist.md](review-checklist.md) to anticipate review feedback 3. Apply changes in this order: - Add new constants to `OpenTelemetryConsts.cs` **only for attributes whose emission is also added in this same PR**. Do not add constants speculatively — if no OpenTelemetry* client in this repo will populate the attribute, defer the constant until the PR that wires up emission and classify the change as 🟢 *Constant not yet emitted* per [change-classification.md](change-classification.md). + - **Choose the correct constant location** for the change's upstream area. See the area-placement table in [implementation-patterns.md §Area placement guidance](implementation-patterns.md#area-placement-guidance) for where each area maps; when placing the constants: + - Use the shared `Microsoft.Extensions.AI/OpenTelemetryConsts.cs` nested classes for shared upstream areas (`GenAI.*` for `gen-ai/*`, and `MCP.*` for `mcp/*` once MCP instrumentation lands). + - Do **not** assume an `OpenAI.*` nested class already exists there. Provider-specific attributes (`openai.*`, `anthropic.*`, `aws-bedrock.*`, `azure-ai-inference.*`) follow the provider package's existing layout. For example, OpenAI tag names are defined as `internal const string` values in `OpenAIClientExtensions.cs`. + - If a provider accumulates enough shared constants to justify a dedicated constants file/class, introduce it explicitly in the same PR rather than assuming one exists. - **Before adding any new helper, method, or internal type**, search `Common/`, `TelemetryHelpers.cs`, `OpenTelemetryLog.cs`, and the sibling OpenTelemetry* client files for existing logic with the same purpose. Reuse or extend rather than introducing a parallel implementation. If the same logic is needed in two or more places, factor it into `Common/` from the start instead of duplicating it per file. The same applies to parallel internal types — unify types with identical shape under a single shared definition. - Add attribute/metric emission to the relevant OpenTelemetry* client classes - - Update version references in doc comments across all files that reference the convention version + - Update version references in doc comments across all files that reference the convention version (see [file-inventory.md §Version References](file-inventory.md#version-references) for the wording-migration guidance) - Update or augment tests 4. Self-review against [review-checklist.md](review-checklist.md) 5. Validate per the **Validation** section in `SKILL.md` diff --git a/.github/skills/update-otel-genai-conventions/references/pr-description.md b/.github/skills/update-otel-genai-conventions/references/pr-description.md index 091ace1b3ec..fe8c40e7d62 100644 --- a/.github/skills/update-otel-genai-conventions/references/pr-description.md +++ b/.github/skills/update-otel-genai-conventions/references/pr-description.md @@ -1,33 +1,141 @@ # PR Title and Description Format -When asked to create or update a PR after implementing semantic-conventions changes, use this guidance. +When asked to create or update a PR after implementing GenAI semantic-conventions changes, use this guidance. ## Title +When a target **GenAI** version number is known (a release or published schema URL exists): + +```text +Update OpenTelemetry GenAI conventions to v{version} +``` + +When no GenAI version number is determined yet -- the common case while `semantic-conventions-genai` is unreleased (no release and no published schema URL) -- use `latest` in place of a version number: + ```text -Update OpenTelemetry gen-ai conventions to v{version} +Update OpenTelemetry GenAI conventions to latest ``` -Use the target semantic-conventions release version for `{version}`. If the PR also includes catch-up work from earlier releases, keep the title focused on the target version and explain the catch-up work in the description. +The GenAI version is independent of core semconv (which has its own version line); do not conflate the two, and do not use `versions.env`'s `SEMCONV_VERSION` (that is the core semconv dependency) as the title version. When a version exists, take `{version}` from the `CHANGELOG.md` release header (Towncrier compiles the `changelog.d/` fragments into it at release time) or the published schema URL (`opentelemetry.io/schemas/gen-ai/X.Y.Z`). While unreleased, keep the title as `latest` and identify the update by its `changelog.d/` fragment snapshot (commit / ref / date) in the body instead of a version number. If the PR also includes catch-up work from earlier convention versions or from the consolidated `open-telemetry/semantic-conventions` repo, keep the title focused on the target (the GenAI version or `latest`) and explain the catch-up work in the description. ## Description -The description should include a changes table derived from the audit table and [change-classification.md](change-classification.md). Group or sort rows by semantic-conventions version and include every analyzed gen-ai change, not only the rows that produced code changes. Use the same red/yellow/green indicators as the classification guide: +The description should include a changes table derived from the audit table and [change-classification.md](change-classification.md). Group or sort rows by GenAI version and include every analyzed change, not only the rows that produced code changes. When no GenAI version number is determined yet, use `latest` in the **Version** column and record the `changelog.d/` fragment snapshot (commit / ref / date) you audited in the description. Use the same red/yellow/green indicators as the classification guide: - 🟢 for no action required - 🟡 for minor action required - 🔴 for code change required -Use this table shape: +Use this table shape (the **Area** column makes it obvious which package each row targets): ```markdown -| Version | Indicator | Semantic-conventions change | Classification | Compensating change / rationale | -|---|:---:|---|---|---| -| v1.XX | 🔴 | `gen_ai.example.attribute` added | New required attribute | Added constant, emission, and tests in `{files}`. | -| v1.XX | 🟡 | Convention version reference changed | Version bump | Updated OpenTelemetry* doc comments. | -| v1.XX | 🟢 | Server-side-only span attribute added | Server-side only | No client-side instrumentation change needed. | +| Version | Area | Indicator | Semantic-conventions change | Classification | Compensating change / rationale | +|---|---|:---:|---|---|---| +| vX.Y.Z | `gen-ai` | 🔴 | `gen_ai.example.attribute` added | New required attribute | Added constant, emission, and tests in `{files}`. | +| vX.Y.Z | `gen-ai` | 🟡 | Convention version reference changed | Version bump | Updated OpenTelemetry* doc comments. | +| vX.Y.Z | `gen-ai` | 🟢 | Server-side-only span attribute added | Server-side only | No client-side instrumentation change needed. | +| vX.Y.Z | `openai` | 🔴 | `openai.example.attribute` added | New required attribute | Added to `Microsoft.Extensions.AI.OpenAI` provider package. | +| vX.Y.Z | `mcp` | 🟢 | `mcp.example.attribute` added | N/A — No client | No MCP instrumentation in this repo today. | ``` For each row, describe the compensating change made, or explain why no change was made (already implemented, no local source, no client exists, server-side only, documentation only, etc.). +When the PR includes catch-up work whose source PRs live in the consolidated `open-telemetry/semantic-conventions` repo (earlier `area:gen-ai` work, before these conventions moved), link to those PRs explicitly using the `open-telemetry/semantic-conventions#NNN` form so reviewers can disambiguate them from `semantic-conventions-genai` PR numbers. + Keep release-specific findings in the PR description or implementation summary; do not add them to the skill references unless they are durable cross-release guidance. + +## Upstream-scan tracking PR body template + +A recurring **upstream-scan tracking PR** records the state of the last upstream scan and lists every merged `Unreleased` change and every open upstream PR with its applicability to this repo. This skill is responsible for producing that PR's full title and body. Assemble the body in the order below, and **keep the machine-readable tracking state and the refresh instructions at the very bottom** so the human-facing content (what shipped, then the applicability tables) leads. + +### 1. Status note (optional) + +While `semantic-conventions-genai` is unreleased, lead with a short blockquote noting the PR is draft pending the first release and that both conventions are Development stability: + +```markdown +> **Draft** pending the first release of +> [open-telemetry/semantic-conventions-genai](https://github.com/open-telemetry/semantic-conventions-genai). +> Both conventions are **Development** stability and **unreleased**. Merge once they ship in a tagged release. +``` + +### 2. What this PR implements + +A compact table of the convention changes this PR actually implements, with the upstream PR link and the compensating change, followed by a one-line **Validation** summary (build TFMs + warning count, test counts, public-API-surface impact, and the doc-comment version reference state): + +```markdown +## What this PR implements + +| Area | Convention | Upstream | Compensating change | +|---|---|---|---| +| `gen-ai` | `gen_ai.example.attribute` | [semantic-conventions-genai#NNN](https://github.com/open-telemetry/semantic-conventions-genai/pull/NNN) | Emit on chat spans in `OpenTelemetryChatClient`. | + +Validation: build clean (net8.0/net9.0/net10.0, 0 warnings); N tests pass. No public API surface change; doc-comment version reference left at `vX.Y`. +``` + +### 3. Upstream scan tracking tables + +Two tables -- merged `Unreleased` changes and in-flight open PRs -- using **one consistent column set** so they read the same way: + +```markdown +## Upstream scan tracking + +Legend: 🔴 implemented here · ✅ already aligned · 🟡 watch/deferred · 🟢 not applicable (no client / docs-only) + +### Merged upstream changes (Unreleased) -- applicability to dotnet/extensions + +| Upstream PR | Area | Change | Applicability | Status | +|---|---|---|:---:|---| +| [#NNN](https://github.com/open-telemetry/semantic-conventions-genai/pull/NNN) | `gen-ai` | `gen_ai.example.attribute` | 🔴 | Implemented in `OpenTelemetryChatClient`. | +| [#NNN](https://github.com/open-telemetry/semantic-conventions-genai/pull/NNN) | `gen-ai` | `top_k` type change | ✅ | Already aligned (`ChatOptions.TopK` is `int?`). | + +### In-flight upstream changes (open PRs) -- applicability if merged + +Filter: open PRs proposing convention changes (exclude pure dependency / CI / chore PRs; list the excluded numbers). + +| Upstream PR | Area | Change | Applicability | Status | +|---|---|---|:---:|---| +| [#NNN](https://github.com/open-telemetry/semantic-conventions-genai/pull/NNN) | `gen-ai` | `document` modality | 🟡 | Watch (additive message serialization). | +| [#NNN](https://github.com/open-telemetry/semantic-conventions-genai/pull/NNN) | `mcp` | tool.call.arguments opt-in | 🟢 | No MCP instrumentation. | +``` + +Column rules for both tables: + +- Keep the **Applicability** column to the color symbol only, and put the explanatory text in the separate **Status** column. The merged-changes table and the in-flight (open-PR) table share these columns exactly; in the in-flight table, **Status** describes what would change *if the PR merged*. +- Keep the **Change** text wrappable so the table fits the screen: browsers do not break long `/`-separated runs (e.g. `entity/identity/finish_reason/...`), and such a run forces the column -- and the whole table -- wider than the viewport. Write multi-segment descriptions with break opportunities (`', '` or `' / '` with surrounding spaces) so the cell can wrap. + +Applicability legend (symbol-only in the Applicability column): + +- 🔴 implemented here +- ✅ already aligned (no change needed) +- 🟡 watch / deferred +- 🟢 not applicable (no client / docs-only / other repo) + +### 4. Tracking state -- very bottom + +Place the machine-readable scan state at the **very bottom** of the body, after the applicability tables. The body **ends with this block** -- do not append a refresh procedure or any other section after it. The state lives in an HTML-comment-delimited block so the next run can parse it: + +````markdown +## Tracking state + + +```yaml +Upstream-Repo: open-telemetry/semantic-conventions-genai +Upstream-Scan-Ref: # optional inline note on what changed since the prior ref +Upstream-Scan-Date: +Upstream-Release: none # Unreleased; Towncrier fragments under changelog.d/ +Core-Semconv-Dependency: vX.Y.Z # versions.env SEMCONV_VERSION (core dep, NOT the GenAI version) +DotnetExtensions-Implemented-Version: vX.Y # doc-comment version reference currently in source +``` + +```` + +## Refreshing the tracking PR + +The PR body carries only the tracking state block; the refresh logic lives in **this skill**, not in the PR body. During the skill's **Existing dotnet/extensions PR Preflight**, treat the tracking PR as the **scan record** -- not a blocking duplicate -- and refresh it as follows: + +1. Invoke the skill in **Mode 1: Audit** -- the skill owns this PR's title and body. +2. Read the `otel-genai-tracking` state block; take `Upstream-Scan-Ref` as the prior scan point. +3. Per the skill's **Input Handling**, run `git log Upstream-Scan-Ref..main` on `open-telemetry/semantic-conventions-genai` and re-list the `changelog.d/` fragments and the open PRs. +4. Classify each new or changed item with the [change-classification](change-classification.md) framework against the current `Microsoft.Extensions.AI` instrumentation, and update both applicability tables. +5. Advance `Upstream-Scan-Ref` / `Upstream-Scan-Date` (and `Core-Semconv-Dependency` / `DotnetExtensions-Implemented-Version` if they moved) in the state block. +6. If the GenAI repo cut a release, follow the skill's version-reference migration (Gotchas + [file-inventory.md §Version References](file-inventory.md#version-references)) to bump and migrate the doc-comment version in lockstep. diff --git a/.github/skills/update-otel-genai-conventions/references/prompt-template.md b/.github/skills/update-otel-genai-conventions/references/prompt-template.md index e0013b0260e..0a04f2868f4 100644 --- a/.github/skills/update-otel-genai-conventions/references/prompt-template.md +++ b/.github/skills/update-otel-genai-conventions/references/prompt-template.md @@ -4,51 +4,68 @@ Template for generating a structured prompt suitable for delegating convention u ## Template -Fill in the bracketed sections based on the analysis of the semantic-conventions release. +Fill in the bracketed sections based on the analysis of the upstream input — a release, PR set, `changelog.d/` snapshot, or date range from [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai) (or, for catch-up work, from the consolidated `open-telemetry/semantic-conventions` repo). --- ```markdown ## Background -The OpenTelemetry semantic conventions {VERSION} release includes gen-ai changes that require compensating updates in dotnet/extensions. Release notes: {RELEASE_URL} +The OpenTelemetry GenAI semantic conventions changes summarized below +require compensating updates in dotnet/extensions. + +Source of changes: {ONE_OF: release URL | changelog.d/ ref URL | PR set | date range} +{IF_RELEASE} Release notes: {RELEASE_URL} +{IF_CHANGELOG_SNAPSHOT} changelog.d/ snapshot: {CHANGELOG_REF_URL} (Towncrier news fragments at the time of audit) +{IF_DATE_RANGE} Date range: PRs merged to `open-telemetry/semantic-conventions-genai` `main` between {START} and {END} + +> The GenAI conventions are maintained in [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai), which also covers `mcp`, `openai`, `anthropic`, `aws-bedrock`, and `azure-ai-inference` areas (they were previously managed in the consolidated `semantic-conventions` repo); see the skill's Migration Note for context. Compensating changes for `anthropic` land in [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp); for `aws-bedrock` they land in the `BedrockRuntime` service library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net) — flag both as out-of-scope here and open follow-ups there. See the skill's [Cross-repo applicability](https://github.com/dotnet/extensions/blob/main/.github/skills/update-otel-genai-conventions/SKILL.md#cross-repo-applicability) section. Key upstream PRs: {FOR_EACH_UPSTREAM_PR} -- [{PR_TITLE}]({PR_URL}) +- [{PR_TITLE}]({PR_URL}) — area: `{AREA}` {END_FOR_EACH} ## Changes Audit -| Semantic Convention Change | Upstream PR | Classification | Action Required | -|---|---|---|---| +| Area | Semantic Convention Change | Upstream PR | Classification | Action Required | +|---|---|---|---|---| {FOR_EACH_CHANGE} -| `{ATTRIBUTE_OR_CHANGE_NAME}` | [#{PR_NUMBER}]({PR_URL}) | {CLASSIFICATION} | {ACTION} | +| `{AREA}` | `{ATTRIBUTE_OR_CHANGE_NAME}` | [open-telemetry/semantic-conventions-genai#{PR_NUMBER}]({PR_URL}) | {CLASSIFICATION} | {ACTION} | {END_FOR_EACH} ## Required Changes ### 1. Version References -Update the semantic conventions version reference from `v{OLD_VERSION}` to `v{NEW_VERSION}` in doc comments across ALL OpenTelemetry* client files: +Update the GenAI semantic conventions doc-comment reference to `v{NEW_VERSION}` in ALL OpenTelemetry* client files that carry a version comment. If this is the PR that migrates the doc-comment wording from the pre-migration form, also reword each occurrence: {LIST_ALL_FILES_WITH_VERSION_REFERENCE} -The doc comment pattern to update: +Pre-migration wording: ```csharp /// Semantic Conventions for Generative AI systems v{OLD_VERSION}, ``` +→ target wording: +```csharp +/// GenAI Semantic Conventions v{NEW_VERSION}, +``` + +If the wording was already migrated in an earlier PR, just bump the version: +```csharp +/// GenAI Semantic Conventions v{OLD_VERSION}, +``` → ```csharp -/// Semantic Conventions for Generative AI systems v{NEW_VERSION}, +/// GenAI Semantic Conventions v{NEW_VERSION}, ``` ### 2. New Constants -Add these constants to `src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs`: +Add these constants to `src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs` (or to the corresponding provider package's constants file for `openai.*`, `anthropic.*`, etc.): {FOR_EACH_NEW_CONSTANT} -In the `{PARENT_CLASS}` nested class: +In the `{PARENT_CLASS}` nested class (`{PARENT_CLASS}` corresponds to the upstream area: `GenAI` for `gen-ai/*`, `MCP` for `mcp/*`, `OpenAI` for `openai/*`, etc.): ```csharp public const string {CONSTANT_NAME} = "{ATTRIBUTE_NAME}"; ``` @@ -81,7 +98,8 @@ Update tests in `{TEST_FILE_PATH}`: {END_FOR_EACH} Reference the `update-otel-genai-conventions` skill in `.github/skills/` for: -- Implementation patterns in `references/implementation-patterns.md` +- Migration context in `SKILL.md` (§Migration Note) +- Implementation patterns in `references/implementation-patterns.md` (including area placement guidance) - Testing guide in `references/testing-guide.md` - Review checklist in `references/review-checklist.md` @@ -90,14 +108,14 @@ Reference the `update-otel-genai-conventions` skill in `.github/skills/` for: After implementing changes: 1. Restore, generate the AI-filtered solution, build, and run the tests using the Linux/macOS commands in `.github/skills/update-otel-genai-conventions/references/build-commands.md` 2. If the public API surface changed, run `pwsh ./scripts/MakeApiBaselines.ps1` and keep only the baselines for the libraries actually changed -3. Verify no remaining references to the old version: `grep -rn "v{OLD_VERSION}" src/Libraries/Microsoft.Extensions.AI/` +3. Verify no remaining references to the old version using the transitional regex from `references/file-inventory.md`: `grep -rEn "Semantic Conventions for Generative AI systems v{OLD_VERSION}|GenAI Semantic Conventions v{OLD_VERSION}" src/Libraries/Microsoft.Extensions.AI/` ``` --- ## Prompt Quality Guidelines -Based on analysis of successful CCA prompts (PRs #7379, #7382, #7322): +Based on analysis of successful CCA prompts (PRs #7379, #7382, #7322 — all predate the move, from when these conventions were managed in the consolidated `semantic-conventions` repo, but the prompt-shape lessons still apply): ### What makes a good prompt @@ -107,6 +125,8 @@ Based on analysis of successful CCA prompts (PRs #7379, #7382, #7322): 4. **Constant values** — specify the exact string values for new OTel attribute names 5. **Test expectations** — specify which test file and whether to augment existing tests or create new ones 6. **Validation commands** — include the build/test commands to run +7. **Disambiguated PR references** — always use the `open-telemetry/semantic-conventions-genai#NNN` form (or `open-telemetry/semantic-conventions#NNN` for catch-up) so PR numbers don't collide across repos +8. **Area on every change row** — so the implementer knows whether each item belongs in `Microsoft.Extensions.AI` or a provider package ### What to avoid @@ -114,6 +134,8 @@ Based on analysis of successful CCA prompts (PRs #7379, #7382, #7322): 2. **Missing files** — forgetting to update version references in all OpenTelemetry* files 3. **Wrong approach** — specifying `Activity.AddEvent` when `ILogger` should be used for events 4. **Incomplete scope** — only covering chat client when embedding generator also needs changes +5. **Wrong package** — putting `openai.*` (or any provider-specific) attributes in `Microsoft.Extensions.AI` instead of the provider package +6. **Bare `#NNN` PR refs** — PR numbers are not interchangeable between the two repos ### Prompt size guidance diff --git a/.github/skills/update-otel-genai-conventions/references/review-checklist.md b/.github/skills/update-otel-genai-conventions/references/review-checklist.md index ea1d9124527..e4ceabc1f3b 100644 --- a/.github/skills/update-otel-genai-conventions/references/review-checklist.md +++ b/.github/skills/update-otel-genai-conventions/references/review-checklist.md @@ -47,14 +47,16 @@ Review checklist for gen-ai convention changes. Based on patterns from past PR r **Past feedback**: PR #7379 — stephentoub asked "do we already have tests validating error.type? If so, can you just augment those". ### 6. Version Reference Completeness -- [ ] All files with a gen-ai semantic conventions version reference use the same version before starting the update +- [ ] All files with a GenAI semantic conventions version reference use the same version before starting the update - [ ] ALL OpenTelemetry* client files with a version reference have that reference updated -- [ ] Grep confirms no remaining references to the old version: `grep -rn "v1.OLD" src/Libraries/Microsoft.Extensions.AI/` +- [ ] If the next convention update is the one that migrates the doc-comment wording from `Semantic Conventions for Generative AI systems v1.XX` to `GenAI Semantic Conventions vX.Y.Z` (per [file-inventory.md §Wording migration](file-inventory.md#wording-migration)), every matched file is migrated in the same PR — no transitional drift left behind. +- [ ] Grep confirms no remaining references to the old version. Use the transitional regex while the wording migration is pending: `grep -rEn "Semantic Conventions for Generative AI systems v(OLD)|GenAI Semantic Conventions v(OLD)" src/Libraries/Microsoft.Extensions.AI/`. After the wording is migrated everywhere, simplify to `grep -rn "GenAI Semantic Conventions v(OLD)" src/Libraries/Microsoft.Extensions.AI/`. ### 7. Constants Organization - [ ] New constants added to appropriate nested class in `OpenTelemetryConsts.cs` - [ ] Constant names follow PascalCase convention - [ ] String values match the semantic convention attribute names exactly +- [ ] **Area-aware nesting**: attributes from upstream `mcp/`, `openai/`, etc. belong in their own nested class (e.g. `OpenTelemetryConsts.MCP.*`, or in a provider-package constants file for `OpenAI.*`) rather than under `GenAI.*`. Do not add MCP or provider attributes to `GenAI.*`. (See [file-inventory.md §Provider-specific instrumentation](file-inventory.md#provider-specific-instrumentation).) - [ ] **No orphan constants**: every newly added constant in `OpenTelemetryConsts.cs` is referenced by at least one emission site added in this PR. Verify with `grep -rn NewConstantName src/Libraries/Microsoft.Extensions.AI/`. If no client populates the attribute, the constant must be removed from this PR and deferred to the PR that adds emission (classify as 🟢 *Constant not yet emitted*). ### 8. Scope Completeness @@ -62,6 +64,7 @@ Review checklist for gen-ai convention changes. Based on patterns from past PR r - [ ] If a change affects embeddings, image generation, speech, etc., those clients are also updated - [ ] Function invocation changes apply to both `FunctionInvokingChatClient` and shared `Common/FunctionInvocationProcessor.cs` - [ ] Realtime function invocation via `FunctionInvokingRealtimeClientSession` is also covered if applicable +- [ ] **Provider-specific scope**: attributes from upstream `openai/`, `anthropic/`, `aws-bedrock/`, `azure-ai-inference/` areas live in the corresponding provider package (e.g. `Microsoft.Extensions.AI.OpenAI` for `openai/`), **not** in `Microsoft.Extensions.AI`. Verify the change landed in the right package and that the provider package's tests cover it. For `anthropic/` and `aws-bedrock/` the corresponding provider package lives in another dotnet SDK repo we contribute to — [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) and the `BedrockRuntime` library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net) respectively (see [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability)); from `dotnet/extensions` they are out of scope — confirm the audit table flags them and that a follow-up has been (or will be) opened in the right SDK repo. **Past feedback**: PR #7379 — stephentoub asked to extend changes to additional client types. diff --git a/.github/skills/update-otel-genai-conventions/references/testing-guide.md b/.github/skills/update-otel-genai-conventions/references/testing-guide.md index cca6886028c..f73bd9318f9 100644 --- a/.github/skills/update-otel-genai-conventions/references/testing-guide.md +++ b/.github/skills/update-otel-genai-conventions/references/testing-guide.md @@ -142,6 +142,26 @@ Test that attributes are omitted (not set to empty/default) when the source data When an attribute appears on both spans and metrics, ensure tests verify both emission points. +## Per-area test files + +When a single instrumented client consumes attributes from multiple +upstream areas in [`open-telemetry/semantic-conventions-genai`](https://github.com/open-telemetry/semantic-conventions-genai) +(e.g. `OpenTelemetryChatClient` consumes `gen-ai/*` plus, in some +provider packages, `openai/*`), the test file still lives **with the +client**. Do not split tests by upstream area — keep all assertions for a +given client in that client's test file. + +Provider-specific attributes (`openai.*`, `anthropic.*`, +`aws-bedrock.*`, `azure-ai-inference.*`) are tested in the corresponding +provider package's test project (e.g. +`test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/` for `openai.*`). +For `anthropic.*` and `aws-bedrock.*` the corresponding provider +package — and therefore its test project — lives in another dotnet SDK +repo we contribute to: [`anthropics/anthropic-sdk-csharp`](https://github.com/anthropics/anthropic-sdk-csharp) +and the `BedrockRuntime` library of [`aws/aws-sdk-net`](https://github.com/aws/aws-sdk-net), +respectively (see [SKILL.md §Cross-repo applicability](../SKILL.md#cross-repo-applicability)); +follow that repo's own test layout when running this skill there. + ## Build and Test Commands See [build-commands.md](build-commands.md) for the canonical Windows and Linux/macOS forms, including the faster `dotnet test --filter` invocation for inner-loop iteration. diff --git a/Directory.Build.props b/Directory.Build.props index 213d4b272b6..e98d137cd11 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -104,7 +104,7 @@ Run tests with the VS Test Runner (dotnet test) instead of the XUnit Test runner (dotnet exec). This is needed to produce Cobertura code coverage. See the targets file to more information. --> - true + true diff --git a/Directory.Build.targets b/Directory.Build.targets index 485395d60c6..5e6ef0f2764 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -92,8 +92,8 @@ - - <_BlameArgs>--blame --blame-crash --blame-crash-dump-type full --blame-hang --blame-hang-dump-type full --blame-hang-timeout 6m + + <_BlameArgs Condition="'$(UseMicrosoftTestingPlatformRunner)' != 'true'">--blame --blame-crash --blame-crash-dump-type full --blame-hang --blame-hang-dump-type full --blame-hang-timeout 6m $(TestRunnerAdditionalArguments) $(_BlameArgs) diff --git a/NuGet.config b/NuGet.config index c487fe90662..d837a0ac838 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,19 +4,19 @@ - + - - + + - - + + - - + + @@ -30,19 +30,19 @@ - + - - + + - - + + - - + + diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml index 6db23e8e747..87fd40ba2dd 100644 --- a/azure-pipelines-public.yml +++ b/azure-pipelines-public.yml @@ -131,7 +131,6 @@ stages: repoTestResultsPath: $(Build.Arcade.TestResultsPath) skipQualityGates: ${{ eq(variables['SkipQualityGates'], 'true') }} isWindows: true - warnAsError: 0 runAsPublic: true # ---------------------------------------------------------------- @@ -163,7 +162,6 @@ stages: repoTestResultsPath: $(Build.Arcade.TestResultsPath) skipQualityGates: ${{ eq(variables['SkipQualityGates'], 'true') }} isWindows: false - warnAsError: 0 runAsPublic: true @@ -209,50 +207,3 @@ stages: displayName: Init toolset - template: /eng/pipelines/templates/VerifyCoverageReport.yml - - -# ---------------------------------------------------------------- -# This stage only performs a build treating warnings as errors -# to detect any kind of code style violations -# ---------------------------------------------------------------- -- stage: correctness - displayName: Correctness - dependsOn: [] - variables: - - template: /eng/common/templates/variables/pool-providers.yml - jobs: - - template: /eng/common/templates/jobs/jobs.yml - parameters: - enableMicrobuild: true - enableTelemetry: true - runAsPublic: true - workspace: - clean: all - - jobs: - - job: WarningsCheck - timeoutInMinutes: 180 - - pool: - name: $(DncEngPublicBuildPool) - demands: ImageOverride -equals windows.vs2022.amd64.open - - variables: - - _buildScript: $(Build.SourcesDirectory)/build.cmd -ci -NativeToolsOnMachine - - preSteps: - - checkout: self - clean: true - persistCredentials: true - fetchDepth: 1 - - steps: - - template: /eng/pipelines/templates/BuildAndTest.yml - parameters: - buildScript: $(_buildScript) - buildConfig: $(_BuildConfig) - repoLogPath: $(Build.Arcade.LogsPath) - repoTestResultsPath: $(Build.Arcade.TestResultsPath) - skipTests: true - skipQualityGates: true - isWindows: true diff --git a/azure-pipelines-unofficial.yml b/azure-pipelines-unofficial.yml index ef6c4eb7f49..46b850e6233 100644 --- a/azure-pipelines-unofficial.yml +++ b/azure-pipelines-unofficial.yml @@ -207,50 +207,3 @@ extends: - template: /eng/pipelines/templates/VerifyCoverageReport.yml - - # ---------------------------------------------------------------- - # This stage only performs a build treating warnings as errors - # to detect any kind of code style violations - # ---------------------------------------------------------------- - - stage: correctness - displayName: Correctness - dependsOn: [] - variables: - - template: /eng/common/templates-official/variables/pool-providers.yml@self - jobs: - - template: /eng/common/templates-official/jobs/jobs.yml@self - parameters: - enableMicrobuild: true - enableTelemetry: true - runAsPublic: ${{ variables['runAsPublic'] }} - workspace: - clean: all - - jobs: - - job: WarningsCheck - timeoutInMinutes: 180 - - pool: - name: NetCore1ESPool-Internal - image: 1es-ubuntu-2204 - os: linux - - variables: - - _buildScript: $(Build.SourcesDirectory)/build.sh --ci - - preSteps: - - checkout: self - clean: true - persistCredentials: true - fetchDepth: 1 - - steps: - - template: '\eng\pipelines\templates\BuildAndTest.yml' - parameters: - buildScript: $(_buildScript) - buildConfig: $(_BuildConfig) - repoLogPath: $(Build.Arcade.LogsPath) - repoTestResultsPath: $(Build.Arcade.TestResultsPath) - skipTests: true - skipQualityGates: true - isWindows: false diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 214256dd567..52912bf501f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -266,62 +266,12 @@ extends: skipQualityGates: ${{ eq(variables['SkipQualityGates'], 'true') }} isWindows: false - # ---------------------------------------------------------------- - # This stage only performs a build treating warnings as errors - # to detect any kind of code style violations - # ---------------------------------------------------------------- - - stage: correctness - displayName: Correctness - dependsOn: [] - variables: - - template: /eng/common/templates-official/variables/pool-providers.yml@self - jobs: - - template: /eng/common/templates-official/jobs/jobs.yml@self - parameters: - enableMicrobuild: true - enableTelemetry: true - runAsPublic: ${{ variables['runAsPublic'] }} - workspace: - clean: all - - jobs: - - job: WarningsCheck - timeoutInMinutes: 180 - - pool: - ${{ if eq(variables['runAsPublic'], 'true') }}: - name: NetCore1ESPool-Internal - image: 1es-ubuntu-2204 - os: linux - - variables: - - _buildScript: $(Build.SourcesDirectory)/build.sh --ci - - preSteps: - - checkout: self - clean: true - persistCredentials: true - fetchDepth: 1 - - steps: - - template: '\eng\pipelines\templates\BuildAndTest.yml' - parameters: - buildScript: $(_buildScript) - buildConfig: $(_BuildConfig) - repoLogPath: $(Build.Arcade.LogsPath) - repoTestResultsPath: $(Build.Arcade.TestResultsPath) - skipTests: true - skipQualityGates: true - isWindows: false - - # Publish and validation steps. Only run in official builds - ${{ if and(ne(variables['runAsPublic'], 'true'), notin(variables['Build.Reason'], 'PullRequest')) }}: - template: /eng/common/templates-official/post-build/post-build.yml@self parameters: validateDependsOn: - build - - correctness publishingInfraVersion: 3 enableSymbolValidation: false enableSigningValidation: false diff --git a/eng/MSBuild/LegacySupport.props b/eng/MSBuild/LegacySupport.props index 20fe1187732..82756c73912 100644 --- a/eng/MSBuild/LegacySupport.props +++ b/eng/MSBuild/LegacySupport.props @@ -1,89 +1,89 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 88a8f2b4ec8..220182653aa 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -1,222 +1,222 @@ - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-runtime - f2c8152eed158e72950025393fde498c90a57a6b + d839c41c85988aadc213e8e42269ecd7883a1790 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-aspnetcore - 5edf41b9c09952f18e404ad38e25670991c1b513 + a95d6599f37762ec8394ba9ca01e8263b2e36a26 - + https://dev.azure.com/dnceng/internal/_git/dotnet-efcore - 46c88f8ca38ff2f5b3c202f4d016f23918ab62e8 + 0d9843b88793b08762c73ef59a9083357e602ef5 - + https://github.com/dotnet/arcade - c6213589e6917c4508c966c282eedbe4efda13e5 + 1373629deb1e04f3e8e66fb68bb48ae36479c5ef - + https://github.com/dotnet/arcade - c6213589e6917c4508c966c282eedbe4efda13e5 + 1373629deb1e04f3e8e66fb68bb48ae36479c5ef - + https://github.com/dotnet/arcade - c6213589e6917c4508c966c282eedbe4efda13e5 + 1373629deb1e04f3e8e66fb68bb48ae36479c5ef diff --git a/eng/Versions.props b/eng/Versions.props index b9725428870..1917b8178cd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -1,7 +1,7 @@ 10 - 7 + 8 0 preview 1 @@ -33,117 +33,117 @@ --> - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 - 9.0.17 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 + 9.0.18 - 9.0.17 + 9.0.18 - 10.0.0-beta.26270.133 + 10.0.0-beta.26326.116 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 - 10.0.9 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 + 10.0.10 - 10.0.9 + 10.0.10 - 10.0.0-beta.26270.133 + 10.0.0-beta.26326.116 @@ -168,8 +168,8 @@ 8.0.0 8.0.2 8.0.0 - 8.0.28 - 8.0.28 + 8.0.29 + 8.0.29 8.0.0 8.0.1 8.0.1 @@ -180,24 +180,24 @@ 8.0.1 8.0.1 8.0.1 - 8.0.3 + 8.0.4 8.0.0 8.0.1 8.0.6 8.0.0 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 - 8.0.28 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 + 8.0.29 - 8.0.28 + 8.0.29 4.8.0 3.3.4 - - 2.9.3 - - 2.8.2 + + 3.2.2 + 3.1.5 + 1.9.1 9.7.0 - 1.67.0-preview 0.43.0 diff --git a/eng/common/core-templates/steps/publish-logs.yml b/eng/common/core-templates/steps/publish-logs.yml index 4eed0312b80..694f55a926e 100644 --- a/eng/common/core-templates/steps/publish-logs.yml +++ b/eng/common/core-templates/steps/publish-logs.yml @@ -33,9 +33,6 @@ steps: '$(publishing-dnceng-devdiv-code-r-build-re)' '$(dn-bot-all-orgs-artifact-feeds-rw)' '$(akams-client-id)' - '$(microsoft-symbol-server-pat)' - '$(symweb-symbol-server-pat)' - '$(dnceng-symbol-server-pat)' '$(dn-bot-all-orgs-build-rw-code-rw)' '$(System.AccessToken)' ${{parameters.CustomSensitiveDataList}} diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index 8abfb71f727..3150ccac6fc 100755 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -5,10 +5,11 @@ set -e usage() { echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [llvmx[.y]] [--skipunmount] --rootfsdir ]" - echo "BuildArch can be: arm(default), arm64, armel, armv6, loongarch64, ppc64le, riscv64, s390x, x64, x86" + echo "BuildArch can be: arm(default), arm64, loongarch64, ppc64le, riscv64, s390x, x64, x86" echo "CodeName - optional, Code name for Linux, can be: xenial(default), zesty, bionic, alpine" echo " for alpine can be specified with version: alpineX.YY or alpineedge" echo " for FreeBSD can be: freebsd13, freebsd14" + echo " for OpenBSD can be: openbsd" echo " for illumos can be: illumos" echo " for Haiku can be: haiku." echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FreeBSD" @@ -27,6 +28,8 @@ __BuildArch=arm __AlpineArch=armv7 __FreeBSDArch=arm __FreeBSDMachineArch=armv7 +__OpenBSDArch=arm +__OpenBSDMachineArch=armv7 __IllumosArch=arm7 __HaikuArch=arm __QEMUArch=arm @@ -72,8 +75,8 @@ __AlpinePackages+=" krb5-dev" __AlpinePackages+=" openssl-dev" __AlpinePackages+=" zlib-dev" -__FreeBSDBase="13.4-RELEASE" -__FreeBSDPkg="1.21.3" +__FreeBSDBase="13.5-RELEASE" +__FreeBSDPkg="2.7.5" __FreeBSDABI="13" __FreeBSDPackages="libunwind" __FreeBSDPackages+=" icu" @@ -82,6 +85,13 @@ __FreeBSDPackages+=" openssl" __FreeBSDPackages+=" krb5" __FreeBSDPackages+=" terminfo-db" +__OpenBSDVersion="7.8" +__OpenBSDPackages="heimdal-libs" +__OpenBSDPackages+=" icu4c" +__OpenBSDPackages+=" libinotify" +__OpenBSDPackages+=" openssl" +__OpenBSDPackages+=" e2fsprogs" + __IllumosPackages="icu" __IllumosPackages+=" mit-krb5" __IllumosPackages+=" openssl" @@ -130,7 +140,6 @@ __AlpineKeys=' 616db30d:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpUpyWDWjlUk3smlWeA0\nlIMW+oJ38t92CRLHH3IqRhyECBRW0d0aRGtq7TY8PmxjjvBZrxTNDpJT6KUk4LRm\na6A6IuAI7QnNK8SJqM0DLzlpygd7GJf8ZL9SoHSH+gFsYF67Cpooz/YDqWrlN7Vw\ntO00s0B+eXy+PCXYU7VSfuWFGK8TGEv6HfGMALLjhqMManyvfp8hz3ubN1rK3c8C\nUS/ilRh1qckdbtPvoDPhSbTDmfU1g/EfRSIEXBrIMLg9ka/XB9PvWRrekrppnQzP\nhP9YE3x/wbFc5QqQWiRCYyQl/rgIMOXvIxhkfe8H5n1Et4VAorkpEAXdsfN8KSVv\nLSMazVlLp9GYq5SUpqYX3KnxdWBgN7BJoZ4sltsTpHQ/34SXWfu3UmyUveWj7wp0\nx9hwsPirVI00EEea9AbP7NM2rAyu6ukcm4m6ATd2DZJIViq2es6m60AE6SMCmrQF\nwmk4H/kdQgeAELVfGOm2VyJ3z69fQuywz7xu27S6zTKi05Qlnohxol4wVb6OB7qG\nLPRtK9ObgzRo/OPumyXqlzAi/Yvyd1ZQk8labZps3e16bQp8+pVPiumWioMFJDWV\nGZjCmyMSU8V6MB6njbgLHoyg2LCukCAeSjbPGGGYhnKLm1AKSoJh3IpZuqcKCk5C\n8CM1S15HxV78s9dFntEqIokCAwEAAQ== 66ba20fe:MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtfB12w4ZgqsXWZDfUAV/\n6Y4aHUKIu3q4SXrNZ7CXF9nXoAVYrS7NAxJdAodsY3vPCN0g5O8DFXR+390LdOuQ\n+HsGKCc1k5tX5ZXld37EZNTNSbR0k+NKhd9h6X3u6wqPOx7SIKxwAQR8qeeFq4pP\nrt9GAGlxtuYgzIIcKJPwE0dZlcBCg+GnptCUZXp/38BP1eYC+xTXSL6Muq1etYfg\nodXdb7Yl+2h1IHuOwo5rjgY5kpY7GcAs8AjGk3lDD/av60OTYccknH0NCVSmPoXK\nvrxDBOn0LQRNBLcAfnTKgHrzy0Q5h4TNkkyTgxkoQw5ObDk9nnabTxql732yy9BY\ns+hM9+dSFO1HKeVXreYSA2n1ndF18YAvAumzgyqzB7I4pMHXq1kC/8bONMJxwSkS\nYm6CoXKyavp7RqGMyeVpRC7tV+blkrrUml0BwNkxE+XnwDRB3xDV6hqgWe0XrifD\nYTfvd9ScZQP83ip0r4IKlq4GMv/R5shcCRJSkSZ6QSGshH40JYSoiwJf5FHbj9ND\n7do0UAqebWo4yNx63j/wb2ULorW3AClv0BCFSdPsIrCStiGdpgJDBR2P2NZOCob3\nG9uMj+wJD6JJg2nWqNJxkANXX37Qf8plgzssrhrgOvB0fjjS7GYhfkfmZTJ0wPOw\nA8+KzFseBh4UFGgue78KwgkCAwEAAQ== ' -__Keyring= __KeyringFile="/usr/share/keyrings/ubuntu-archive-keyring.gpg" __SkipSigCheck=0 __SkipEmulation=0 @@ -153,6 +162,10 @@ while :; do __AlpineArch=armv7 __QEMUArch=arm ;; + armel) + # this is only used for tizen-build-rootfs.sh + __BuildArch=armel + ;; arm64) __BuildArch=arm64 __UbuntuArch=arm64 @@ -160,31 +173,8 @@ while :; do __QEMUArch=aarch64 __FreeBSDArch=arm64 __FreeBSDMachineArch=aarch64 - ;; - armel) - __BuildArch=armel - __UbuntuArch=armel - __UbuntuRepo="http://archive.debian.org/debian/" - __CodeName=buster - __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" - __LLDB_Package="liblldb-6.0-dev" - __UbuntuPackages="${__UbuntuPackages// libomp-dev/}" - __UbuntuPackages="${__UbuntuPackages// libomp5/}" - __UbuntuSuites= - ;; - armv6) - __BuildArch=armv6 - __UbuntuArch=armhf - __QEMUArch=arm - __UbuntuRepo="http://raspbian.raspberrypi.org/raspbian/" - __CodeName=buster - __KeyringFile="/usr/share/keyrings/raspbian-archive-keyring.gpg" - __LLDB_Package="liblldb-6.0-dev" - __UbuntuSuites= - - if [[ -e "$__KeyringFile" ]]; then - __Keyring="--keyring $__KeyringFile" - fi + __OpenBSDArch=arm64 + __OpenBSDMachineArch=aarch64 ;; loongarch64) __BuildArch=loongarch64 @@ -193,10 +183,6 @@ while :; do __UbuntuArch=loong64 __UbuntuSuites=unreleased __LLDB_Package="liblldb-19-dev" - - if [[ "$__CodeName" == "sid" ]]; then - __UbuntuRepo="http://ftp.ports.debian.org/debian-ports/" - fi ;; riscv64) __BuildArch=riscv64 @@ -212,7 +198,7 @@ while :; do __AlpineArch=ppc64le __QEMUArch=ppc64le __UbuntuArch=ppc64el - __UbuntuRepo="http://ports.ubuntu.com/ubuntu-ports/" + __UbuntuRepo="https://ports.ubuntu.com/ubuntu-ports/" __UbuntuPackages="${__UbuntuPackages// libunwind8-dev/}" __UbuntuPackages="${__UbuntuPackages// libomp-dev/}" __UbuntuPackages="${__UbuntuPackages// libomp5/}" @@ -223,7 +209,7 @@ while :; do __AlpineArch=s390x __QEMUArch=s390x __UbuntuArch=s390x - __UbuntuRepo="http://ports.ubuntu.com/ubuntu-ports/" + __UbuntuRepo="https://ports.ubuntu.com/ubuntu-ports/" __UbuntuPackages="${__UbuntuPackages// libunwind8-dev/}" __UbuntuPackages="${__UbuntuPackages// libomp-dev/}" __UbuntuPackages="${__UbuntuPackages// libomp5/}" @@ -235,15 +221,17 @@ while :; do __UbuntuArch=amd64 __FreeBSDArch=amd64 __FreeBSDMachineArch=amd64 + __OpenBSDArch=amd64 + __OpenBSDMachineArch=amd64 __illumosArch=x86_64 __HaikuArch=x86_64 - __UbuntuRepo="http://archive.ubuntu.com/ubuntu/" + __UbuntuRepo="https://archive.ubuntu.com/ubuntu/" ;; x86) __BuildArch=x86 __UbuntuArch=i386 __AlpineArch=x86 - __UbuntuRepo="http://archive.ubuntu.com/ubuntu/" + __UbuntuRepo="https://archive.ubuntu.com/ubuntu/" ;; lldb*) version="$(echo "$lowerI" | tr -d '[:alpha:]-=')" @@ -295,9 +283,7 @@ while :; do ;; noble) # Ubuntu 24.04 __CodeName=noble - if [[ -z "$__LLDB_Package" ]]; then - __LLDB_Package="liblldb-19-dev" - fi + __LLDB_Package="liblldb-19-dev" ;; stretch) # Debian 9 __CodeName=stretch @@ -305,7 +291,7 @@ while :; do __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ftp.debian.org/debian/" + __UbuntuRepo="https://archive.debian.org/debian/" fi ;; buster) # Debian 10 @@ -314,7 +300,7 @@ while :; do __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://archive.debian.org/debian/" + __UbuntuRepo="https://archive.debian.org/debian/" fi ;; bullseye) # Debian 11 @@ -322,7 +308,7 @@ while :; do __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ftp.debian.org/debian/" + __UbuntuRepo="https://ftp.debian.org/debian/" fi ;; bookworm) # Debian 12 @@ -330,7 +316,7 @@ while :; do __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ftp.debian.org/debian/" + __UbuntuRepo="https://ftp.debian.org/debian/" fi ;; sid) # Debian sid @@ -339,25 +325,21 @@ while :; do # Debian-Ports architectures need different values case "$__UbuntuArch" in - amd64|arm64|armel|armhf|i386|mips64el|ppc64el|riscv64|s390x) + amd64|arm64|armhf|i386|mips64el|ppc64el|riscv64|s390x) __KeyringFile="/usr/share/keyrings/debian-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ftp.debian.org/debian/" + __UbuntuRepo="https://ftp.debian.org/debian/" fi ;; *) __KeyringFile="/usr/share/keyrings/debian-ports-archive-keyring.gpg" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ftp.ports.debian.org/debian-ports/" + __UbuntuRepo="https://ftp.debian.org/debian-ports/" fi ;; esac - - if [[ -e "$__KeyringFile" ]]; then - __Keyring="--keyring $__KeyringFile" - fi ;; tizen) __CodeName= @@ -383,10 +365,14 @@ while :; do ;; freebsd14) __CodeName=freebsd - __FreeBSDBase="14.2-RELEASE" + __FreeBSDBase="14.3-RELEASE" __FreeBSDABI="14" __SkipUnmount=1 ;; + openbsd) + __CodeName=openbsd + __SkipUnmount=1 + ;; illumos) __CodeName=illumos __SkipUnmount=1 @@ -457,7 +443,7 @@ fi __UbuntuPackages+=" ${__LLDB_Package:-}" if [[ -z "$__UbuntuRepo" ]]; then - __UbuntuRepo="http://ports.ubuntu.com/" + __UbuntuRepo="https://ports.ubuntu.com/" fi if [[ -n "$__LLVM_MajorVersion" ]]; then @@ -544,15 +530,15 @@ if [[ "$__CodeName" == "alpine" ]]; then # initialize DB # shellcheck disable=SC2086 "$__ApkToolsDir/apk.static" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/main" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/community" \ -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" --initdb add if [[ "$__AlpineLlvmLibsLookup" == 1 ]]; then # shellcheck disable=SC2086 __AlpinePackages+=" $("$__ApkToolsDir/apk.static" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/main" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/community" \ -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" \ search 'llvm*-libs' | grep -E '^llvm' | sort | tail -1 | sed 's/-[^-]*//2g')" fi @@ -560,8 +546,8 @@ if [[ "$__CodeName" == "alpine" ]]; then # install all packages in one go # shellcheck disable=SC2086 "$__ApkToolsDir/apk.static" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/main" \ - -X "http://dl-cdn.alpinelinux.org/alpine/$version/community" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/main" \ + -X "https://dl-cdn.alpinelinux.org/alpine/$version/community" \ -U $__ApkSignatureArg --root "$__RootfsDir" --arch "$__AlpineArch" $__NoEmulationArg \ add $__AlpinePackages @@ -578,7 +564,7 @@ elif [[ "$__CodeName" == "freebsd" ]]; then curl -SL "https://download.freebsd.org/ftp/releases/${__FreeBSDArch}/${__FreeBSDMachineArch}/${__FreeBSDBase}/base.txz" | tar -C "$__RootfsDir" -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version fi echo "ABI = \"FreeBSD:${__FreeBSDABI}:${__FreeBSDMachineArch}\"; FINGERPRINTS = \"${__RootfsDir}/usr/share/keys\"; REPOS_DIR = [\"${__RootfsDir}/etc/pkg\"]; REPO_AUTOUPDATE = NO; RUN_SCRIPTS = NO;" > "${__RootfsDir}"/usr/local/etc/pkg.conf - echo "FreeBSD: { url: \"pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly\", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"/usr/share/keys/pkg\", enabled: yes }" > "${__RootfsDir}"/etc/pkg/FreeBSD.conf + echo "FreeBSD: { url: \"pkg+https://pkg.FreeBSD.org/\${ABI}/quarterly\", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"/usr/share/keys/pkg\", enabled: yes }" > "${__RootfsDir}"/etc/pkg/FreeBSD.conf mkdir -p "$__RootfsDir"/tmp # get and build package manager if [[ "$__hasWget" == 1 ]]; then @@ -592,9 +578,69 @@ elif [[ "$__CodeName" == "freebsd" ]]; then ./autogen.sh && ./configure --prefix="$__RootfsDir"/host && make -j "$JOBS" && make install rm -rf "$__RootfsDir/tmp/pkg-${__FreeBSDPkg}" # install packages we need. - INSTALL_AS_USER=$(whoami) "$__RootfsDir"/host/sbin/pkg -r "$__RootfsDir" -C "$__RootfsDir"/usr/local/etc/pkg.conf update + INSTALL_AS_USER=$(whoami) IGNORE_OSVERSION=yes "$__RootfsDir"/host/sbin/pkg -r "$__RootfsDir" -C "$__RootfsDir"/usr/local/etc/pkg.conf update # shellcheck disable=SC2086 INSTALL_AS_USER=$(whoami) "$__RootfsDir"/host/sbin/pkg -r "$__RootfsDir" -C "$__RootfsDir"/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages +elif [[ "$__CodeName" == "openbsd" ]]; then + # determine mirrors + OPENBSD_MIRROR="https://cdn.openbsd.org/pub/OpenBSD/$__OpenBSDVersion/$__OpenBSDMachineArch" + + # download base system sets + ensureDownloadTool + + BASE_SETS=(base comp) + for set in "${BASE_SETS[@]}"; do + FILE="${set}${__OpenBSDVersion//./}.tgz" + echo "Downloading $FILE..." + if [[ "$__hasWget" == 1 ]]; then + wget -O- "$OPENBSD_MIRROR/$FILE" | tar -C "$__RootfsDir" -xzpf - + else + curl -SL "$OPENBSD_MIRROR/$FILE" | tar -C "$__RootfsDir" -xzpf - + fi + done + + PKG_MIRROR="https://cdn.openbsd.org/pub/OpenBSD/${__OpenBSDVersion}/packages/${__OpenBSDMachineArch}" + + echo "Installing packages into sysroot..." + + # Fetch package index once + if [[ "$__hasWget" == 1 ]]; then + PKG_INDEX=$(wget -qO- "$PKG_MIRROR/") + else + PKG_INDEX=$(curl -s "$PKG_MIRROR/") + fi + + for pkg in $__OpenBSDPackages; do + PKG_FILE=$(echo "$PKG_INDEX" | grep -Po ">\K${pkg}-[0-9][^\" ]*\.tgz" \ + | sort -V | tail -n1) + + echo "Resolved package filename for $pkg: $PKG_FILE" + + [[ -z "$PKG_FILE" ]] && { echo "ERROR: Package $pkg not found"; exit 1; } + + if [[ "$__hasWget" == 1 ]]; then + wget -O- "$PKG_MIRROR/$PKG_FILE" | tar -C "$__RootfsDir/usr/local" -xzpf - + else + curl -SL "$PKG_MIRROR/$PKG_FILE" | tar -C "$__RootfsDir/usr/local" -xzpf - + fi + done + + echo "Creating versionless symlinks for shared libraries..." + # Find all versioned .so files and create the base .so symlink + for lib in "$__RootfsDir"/usr/lib/lib*.so.*; do + if [ -f "$lib" ]; then + # Extract the filename (e.g., libc++.so.12.0) + VERSIONED_NAME=$(basename "$lib") + # Remove the trailing version numbers (e.g., libc++.so) + BASE_NAME=${VERSIONED_NAME%.so.*}.so + # Create the symlink in the same directory + ln -sf "$VERSIONED_NAME" "$__RootfsDir/usr/lib/$BASE_NAME" + fi + done + + echo "Cleaning up unnecessary paths" + # we don't use executables and kernel in rootfs (as we use host's compiler with -sysroot) + rm -rf "$__RootfsDir/usr/share" "$__RootfsDir/usr/bin" elif [[ "$__CodeName" == "illumos" ]]; then mkdir "$__RootfsDir/tmp" pushd "$__RootfsDir/tmp" @@ -759,6 +805,14 @@ elif [[ "$__CodeName" == "haiku" ]]; then elif [[ -n "$__CodeName" ]]; then __Suites="$__CodeName $(for suite in $__UbuntuSuites; do echo -n "$__CodeName-$suite "; done)" + __SigCheckArgs= + if [[ "$__SkipSigCheck" == "0" ]]; then + if [[ -e "$__KeyringFile" ]]; then + __SigCheckArgs="--keyring $__KeyringFile" + fi + __SigCheckArgs="$__SigCheckArgs --force-check-gpg" + fi + if [[ "$__SkipEmulation" == "1" ]]; then if [[ -z "$AR" ]]; then if command -v ar &>/dev/null; then @@ -774,31 +828,23 @@ elif [[ -n "$__CodeName" ]]; then PYTHON=${PYTHON_EXECUTABLE:-python3} # shellcheck disable=SC2086,SC2046 - echo running "$PYTHON" "$__CrossDir/install-debs.py" --arch "$__UbuntuArch" --mirror "$__UbuntuRepo" --rootfsdir "$__RootfsDir" --artool "$AR" \ + echo running "$PYTHON" "$__CrossDir/install-debs.py" $__SigCheckArgs --arch "$__UbuntuArch" --mirror "$__UbuntuRepo" --rootfsdir "$__RootfsDir" --artool "$AR" \ $(for suite in $__Suites; do echo -n "--suite $suite "; done) \ $__UbuntuPackages # shellcheck disable=SC2086,SC2046 - "$PYTHON" "$__CrossDir/install-debs.py" --arch "$__UbuntuArch" --mirror "$__UbuntuRepo" --rootfsdir "$__RootfsDir" --artool "$AR" \ + "$PYTHON" "$__CrossDir/install-debs.py" $__SigCheckArgs --arch "$__UbuntuArch" --mirror "$__UbuntuRepo" --rootfsdir "$__RootfsDir" --artool "$AR" \ $(for suite in $__Suites; do echo -n "--suite $suite "; done) \ $__UbuntuPackages exit 0 fi - __UpdateOptions= - if [[ "$__SkipSigCheck" == "0" ]]; then - __Keyring="$__Keyring --force-check-gpg" - else - __Keyring= - __UpdateOptions="--allow-unauthenticated --allow-insecure-repositories" - fi - # shellcheck disable=SC2086 - echo running debootstrap "--variant=minbase" $__Keyring --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo" + echo running debootstrap "--variant=minbase" $__SigCheckArgs --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo" # shellcheck disable=SC2086 - if ! debootstrap "--variant=minbase" $__Keyring --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo"; then + if ! debootstrap "--variant=minbase" $__SigCheckArgs --arch "$__UbuntuArch" "$__CodeName" "$__RootfsDir" "$__UbuntuRepo"; then echo "debootstrap failed! dumping debootstrap.log" cat "$__RootfsDir/debootstrap/debootstrap.log" exit 1 @@ -816,6 +862,11 @@ Components: main universe Signed-By: $__KeyringFile EOF + __UpdateOptions= + if [[ "$__SkipSigCheck" == "1" ]]; then + __UpdateOptions="--allow-unauthenticated --allow-insecure-repositories" + fi + # shellcheck disable=SC2086 chroot "$__RootfsDir" apt-get update $__UpdateOptions chroot "$__RootfsDir" apt-get -f -y install diff --git a/eng/common/cross/install-debs.py b/eng/common/cross/install-debs.py index c81eb37e522..1d1dfabf7dc 100644 --- a/eng/common/cross/install-debs.py +++ b/eng/common/cross/install-debs.py @@ -4,6 +4,7 @@ import asyncio import aiohttp import gzip +import hashlib import os import re import shutil @@ -16,7 +17,7 @@ from collections import deque from functools import cmp_to_key -async def download_file(session, url, dest_path, max_retries=3, retry_delay=2, timeout=60): +async def download_file(session, url, dest_path, max_retries=3, retry_delay=2, timeout=60, checksum=None): """Asynchronous file download with retries.""" attempt = 0 while attempt < max_retries: @@ -25,19 +26,25 @@ async def download_file(session, url, dest_path, max_retries=3, retry_delay=2, t if response.status == 200: with open(dest_path, "wb") as f: content = await response.read() + + # verify checksum if provided + if checksum: + sha256 = hashlib.sha256(content).hexdigest() + if sha256 != checksum: + raise Exception(f"SHA256 mismatch for {url}: expected {checksum}, got {sha256}") + f.write(content) print(f"Downloaded {url} at {dest_path}") return else: - print(f"Failed to download {url}, Status Code: {response.status}") - break + raise Exception(f"Failed to download {url}, Status Code: {response.status}") except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e: print(f"Error downloading {url}: {type(e).__name__} - {e}. Retrying...") attempt += 1 await asyncio.sleep(retry_delay) - print(f"Failed to download {url} after {max_retries} attempts.") + raise Exception(f"Failed to download {url} after {max_retries} attempts.") async def download_deb_files_parallel(mirror, packages, tmp_dir): """Download .deb files in parallel.""" @@ -51,11 +58,11 @@ async def download_deb_files_parallel(mirror, packages, tmp_dir): if filename: url = f"{mirror}/{filename}" dest_path = os.path.join(tmp_dir, os.path.basename(filename)) - tasks.append(asyncio.create_task(download_file(session, url, dest_path))) + tasks.append(asyncio.create_task(download_file(session, url, dest_path, checksum=info.get("SHA256")))) await asyncio.gather(*tasks) -async def download_package_index_parallel(mirror, arch, suites): +async def download_package_index_parallel(mirror, arch, suites, check_sig, keyring): """Download package index files for specified suites and components entirely in memory.""" tasks = [] timeout = aiohttp.ClientTimeout(total=60) @@ -63,10 +70,9 @@ async def download_package_index_parallel(mirror, arch, suites): async with aiohttp.ClientSession(timeout=timeout) as session: for suite in suites: for component in ["main", "universe"]: - url = f"{mirror}/dists/{suite}/{component}/binary-{arch}/Packages.gz" - tasks.append(fetch_and_decompress(session, url)) + tasks.append(fetch_and_decompress(session, mirror, arch, suite, component, check_sig, keyring)) - results = await asyncio.gather(*tasks, return_exceptions=True) + results = await asyncio.gather(*tasks) merged_content = "" for result in results: @@ -77,20 +83,75 @@ async def download_package_index_parallel(mirror, arch, suites): return merged_content -async def fetch_and_decompress(session, url): +async def fetch_and_decompress(session, mirror, arch, suite, component, check_sig, keyring): """Fetch and decompress the Packages.gz file.""" - try: - async with session.get(url) as response: - if response.status == 200: - compressed_data = await response.read() - decompressed_data = gzip.decompress(compressed_data).decode('utf-8') - print(f"Downloaded index: {url}") - return decompressed_data - else: - print(f"Skipped index: {url} (doesn't exist)") - return None - except Exception as e: - print(f"Error fetching {url}: {e}") + + path = f"{component}/binary-{arch}/Packages.gz" + url = f"{mirror}/dists/{suite}/{path}" + + async with session.get(url) as response: + if response.status == 200: + compressed_data = await response.read() + decompressed_data = gzip.decompress(compressed_data).decode('utf-8') + print(f"Downloaded index: {url}") + + if check_sig: + # Verify the package index against the sha256 recorded in the Release file + release_file_content = await fetch_release_file(session, mirror, suite, keyring) + packages_sha = parse_release_file(release_file_content, path) + + sha256 = hashlib.sha256(compressed_data).hexdigest() + if sha256 != packages_sha: + raise Exception(f"SHA256 mismatch for {path}: expected {packages_sha}, got {sha256}") + print(f"Checksum verified for {path}") + + return decompressed_data + else: + print(f"Skipped index: {url} (doesn't exist)") + return None + +async def fetch_release_file(session, mirror, suite, keyring): + """Fetch Release and Release.gpg files and verify the signature.""" + + release_url = f"{mirror}/dists/{suite}/Release" + release_gpg_url = f"{mirror}/dists/{suite}/Release.gpg" + + with tempfile.NamedTemporaryFile() as release_file, tempfile.NamedTemporaryFile() as release_gpg_file: + await download_file(session, release_url, release_file.name) + await download_file(session, release_gpg_url, release_gpg_file.name) + + print("Verifying signature of Release with Release.gpg.") + # Use gpgv rather than gpg for verification. gpgv verifies a detached + # signature against a fixed keyring without involving gpg-agent or + # keyboxd, which makes it robust on hosts running GnuPG 2.4+ (e.g. Azure + # Linux) where "gpg --keyring" routes through keyboxd and can fail. + verify_command = ["gpgv"] + if keyring: + verify_command += ["--keyring", keyring] + verify_command += [release_gpg_file.name, release_file.name] + result = subprocess.run(verify_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + if result.returncode != 0: + raise Exception(f"Signature verification failed: {result.stderr.decode('utf-8')}") + + print("Signature verified successfully.") + + with open(release_file.name) as f: + return f.read() + +def parse_release_file(content, path): + """Parses the Release file and returns sha256 checksum of the specified path.""" + + # data looks like this: + # + matches = re.findall(r'^ (\S*) +(\S*) +(\S*)$', content, re.MULTILINE) + + for entry in matches: + # the file has both md5 and sha256 checksums, we want sha256 which has a length of 64 + if entry[2] == path and len(entry[0]) == 64: + return entry[0] + + raise Exception(f"Could not find checksum for {path} in Release file.") def parse_debian_version(version): """Parse a Debian package version into epoch, upstream version, and revision.""" @@ -171,13 +232,15 @@ def parse_package_index(content): filename = fields.get("Filename") depends = fields.get("Depends") provides = fields.get("Provides", None) + sha256 = fields.get("SHA256") # Only update if package_name is not in packages or if the new version is higher if package_name not in packages or compare_debian_versions(version, packages[package_name]["Version"]) > 0: packages[package_name] = { "Version": version, "Filename": filename, - "Depends": depends + "Depends": depends, + "SHA256": sha256 } # Update aliases if package provides any alternatives @@ -233,7 +296,7 @@ def extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool): os.makedirs(extract_dir, exist_ok=True) with tempfile.TemporaryDirectory(dir=tmp_dir) as tmp_subdir: - result = subprocess.run(f"{ar_tool} t {os.path.abspath(deb_file)}", cwd=tmp_subdir, check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + result = subprocess.run([ar_tool, "t", os.path.abspath(deb_file)], cwd=tmp_subdir, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) tar_filename = None for line in result.stdout.decode().splitlines(): @@ -247,7 +310,8 @@ def extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool): tar_file_path = os.path.join(tmp_subdir, tar_filename) print(f"Extracting {tar_filename} from {deb_file}..") - subprocess.run(f"{ar_tool} p {os.path.abspath(deb_file)} {tar_filename} > {tar_file_path}", check=True, shell=True) + with open(tar_file_path, "wb") as outfile: + subprocess.run([ar_tool, "p", os.path.abspath(deb_file), tar_filename], check=True, stdout=outfile, stderr=subprocess.PIPE) file_extension = os.path.splitext(tar_file_path)[1].lower() @@ -268,7 +332,18 @@ def extract_deb_file(deb_file, tmp_dir, extract_dir, ar_tool): raise ValueError(f"Unsupported compression format: {file_extension}") with tarfile.open(tar_file_path, mode) as tar: - tar.extractall(path=extract_dir, filter='fully_trusted') + tar.extractall(path=extract_dir, filter=_rootfs_extraction_filter) + +def _rootfs_extraction_filter(member, dest_path): + """Tarfile extraction filter based on the 'data' filter that additionally + rewrites absolute-target symlinks/hardlinks into rootfs-relative paths. + """ + if (member.issym() or member.islnk()) and os.path.isabs(member.linkname): + link_dir = os.path.dirname(member.name) + new_linkname = os.path.relpath(member.linkname.lstrip('/'), + start=link_dir or '.') + member = member.replace(linkname=new_linkname, deep=False) + return tarfile.data_filter(member, dest_path) def finalize_setup(rootfsdir): lib_dir = os.path.join(rootfsdir, 'lib') @@ -295,24 +370,17 @@ def finalize_setup(rootfsdir): if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate rootfs for .NET runtime on Debian-like OS") - parser.add_argument("--distro", required=False, help="Distro name (e.g., debian, ubuntu, etc.)") parser.add_argument("--arch", required=True, help="Architecture (e.g., amd64, loong64, etc.)") parser.add_argument("--rootfsdir", required=True, help="Destination directory.") parser.add_argument('--suite', required=True, action='append', help='Specify one or more repository suites to collect index data.') - parser.add_argument("--mirror", required=False, help="Mirror (e.g., http://ftp.debian.org/debian-ports etc.)") + parser.add_argument("--mirror", required=True, help="Mirror (e.g., http://ftp.debian.org/debian-ports etc.)") parser.add_argument("--artool", required=False, default="ar", help="ar tool to extract debs (e.g., ar, llvm-ar etc.)") + parser.add_argument("--force-check-gpg", required=False, action='store_true', help="Verify the packages against signatures in Release file.") + parser.add_argument("--keyring", required=False, default='', help="Keyring file to check signature of Release file.") parser.add_argument("packages", nargs="+", help="List of package names to be installed.") args = parser.parse_args() - if args.mirror is None: - if args.distro == "ubuntu": - args.mirror = "http://archive.ubuntu.com/ubuntu" if args.arch in ["amd64", "i386"] else "http://ports.ubuntu.com/ubuntu-ports" - elif args.distro == "debian": - args.mirror = "http://ftp.debian.org/debian-ports" - else: - raise Exception("Unsupported distro") - DESIRED_PACKAGES = args.packages + [ # base packages "dpkg", "busybox", @@ -322,9 +390,16 @@ def finalize_setup(rootfsdir): "debianutils" ] - print(f"Creating rootfs. rootfsdir: {args.rootfsdir}, distro: {args.distro}, arch: {args.arch}, suites: {args.suite}, mirror: {args.mirror}") + print(f"Creating rootfs. rootfsdir: {args.rootfsdir}, arch: {args.arch}, suites: {args.suite}, mirror: {args.mirror}") + + check_sig = args.force_check_gpg + if check_sig and not args.keyring: + print("ERROR: --force-check-gpg requires --keyring to specify a keyring file for signature verification.") + print("Install the appropriate keyring package (e.g., debian-ports-archive-keyring, ubuntu-archive-keyring)") + print("or pass --skipsigcheck to build-rootfs.sh to disable signature checking.") + sys.exit(1) - package_index_content = asyncio.run(download_package_index_parallel(args.mirror, args.arch, args.suite)) + package_index_content = asyncio.run(download_package_index_parallel(args.mirror, args.arch, args.suite, check_sig, args.keyring)) packages_info, aliases = parse_package_index(package_index_content) diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index 0ff85cf0367..f65c689f695 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -3,15 +3,22 @@ set(CROSS_ROOTFS $ENV{ROOTFS_DIR}) # reset platform variables (e.g. cmake 3.25 sets LINUX=1) unset(LINUX) unset(FREEBSD) +unset(OPENBSD) unset(ILLUMOS) unset(ANDROID) unset(TIZEN) unset(HAIKU) set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH}) + +file(GLOB OPENBSD_PROBE "${CROSS_ROOTFS}/etc/signify/openbsd-*.pub") + if(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version) set(CMAKE_SYSTEM_NAME FreeBSD) set(FREEBSD 1) +elseif(OPENBSD_PROBE) + set(CMAKE_SYSTEM_NAME OpenBSD) + set(OPENBSD 1) elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc) set(CMAKE_SYSTEM_NAME SunOS) set(ILLUMOS 1) @@ -52,7 +59,9 @@ elseif(TARGET_ARCH_NAME STREQUAL "arm64") set(TIZEN_TOOLCHAIN "aarch64-tizen-linux-gnu") endif() elseif(FREEBSD) - set(triple "aarch64-unknown-freebsd12") + set(TOOLCHAIN "aarch64-unknown-freebsd14") + elseif(OPENBSD) + set(TOOLCHAIN "aarch64-unknown-openbsd") endif() elseif(TARGET_ARCH_NAME STREQUAL "armel") set(CMAKE_SYSTEM_PROCESSOR armv7l) @@ -108,7 +117,9 @@ elseif(TARGET_ARCH_NAME STREQUAL "x64") set(TIZEN_TOOLCHAIN "x86_64-tizen-linux-gnu") endif() elseif(FREEBSD) - set(triple "x86_64-unknown-freebsd12") + set(TOOLCHAIN "x86_64-unknown-freebsd14") + elseif(OPENBSD) + set(TOOLCHAIN "x86_64-unknown-openbsd") elseif(ILLUMOS) set(TOOLCHAIN "x86_64-illumos") elseif(HAIKU) @@ -148,9 +159,6 @@ if(TIZEN) else() find_toolchain_dir("${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}") endif() - - message(STATUS "TIZEN_TOOLCHAIN_PATH set to: ${TIZEN_TOOLCHAIN_PATH}") - include_directories(SYSTEM ${TIZEN_TOOLCHAIN_PATH}/include/c++) include_directories(SYSTEM ${TIZEN_TOOLCHAIN_PATH}/include/c++/${TIZEN_TOOLCHAIN}) endif() @@ -193,11 +201,11 @@ if(ANDROID) # include official NDK toolchain script include(${CROSS_ROOTFS}/../build/cmake/android.toolchain.cmake) -elseif(FREEBSD) +elseif(FREEBSD OR OPENBSD) # we cross-compile by instructing clang - set(CMAKE_C_COMPILER_TARGET ${triple}) - set(CMAKE_CXX_COMPILER_TARGET ${triple}) - set(CMAKE_ASM_COMPILER_TARGET ${triple}) + set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) + set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) + set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_SYSROOT "${CROSS_ROOTFS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld") @@ -214,13 +222,19 @@ elseif(ILLUMOS) locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) elseif(HAIKU) set(CMAKE_SYSROOT "${CROSS_ROOTFS}") - set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin") set(CMAKE_SYSTEM_PREFIX_PATH "${CROSS_ROOTFS}") set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lssp") set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lssp") - locate_toolchain_exec(gcc CMAKE_C_COMPILER) - locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) + if ("$ENV{CCC_CC}" MATCHES ".*gcc.*") + set(CMAKE_PROGRAM_PATH "${CMAKE_PROGRAM_PATH};${CROSS_ROOTFS}/cross-tools-x86_64/bin") + locate_toolchain_exec(gcc CMAKE_C_COMPILER) + locate_toolchain_exec(g++ CMAKE_CXX_COMPILER) + else() + set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + set(CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/cross-tools-x86_64") + endif() # let CMake set up the correct search paths include(Platform/Haiku) @@ -291,7 +305,7 @@ endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|loongarch64|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU) +if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|loongarch64|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT FREEBSD AND NOT OPENBSD) OR ILLUMOS OR HAIKU) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) diff --git a/eng/common/native/LocateNativeCompiler.targets b/eng/common/native/LocateNativeCompiler.targets new file mode 100644 index 00000000000..028b33d9444 --- /dev/null +++ b/eng/common/native/LocateNativeCompiler.targets @@ -0,0 +1,27 @@ + + + + + clang + $(ROOTFS_DIR) + + + + + + + + $(_CC_LDFLAGS.SubString(0, $(_CC_LDFLAGS.IndexOf(';')))) + <_LDFLAGS>$(_CC_LDFLAGS.SubString($([MSBuild]::Add($(_CC_LDFLAGS.IndexOf(';')), 1)))) + lld + + + diff --git a/eng/common/native/NativeAotSupported.props b/eng/common/native/NativeAotSupported.props new file mode 100644 index 00000000000..559a6663929 --- /dev/null +++ b/eng/common/native/NativeAotSupported.props @@ -0,0 +1,26 @@ + + + + + <_NativeAotSupportedOS Condition=" + '$(TargetOS)' != 'browser' and + '$(TargetOS)' != 'haiku' and + '$(TargetOS)' != 'illumos' and + '$(TargetOS)' != 'netbsd' and + '$(TargetOS)' != 'solaris' + ">true + + + <_NativeAotSupportedArch Condition=" + '$(TargetArchitecture)' != 'wasm' and + ('$(TargetArchitecture)' != 'x86' or '$(TargetOS)' == 'windows') + ">true + + true + + + diff --git a/eng/common/native/init-distro-rid.sh b/eng/common/native/init-distro-rid.sh index 83ea7aab0e0..8fc6d2fec78 100644 --- a/eng/common/native/init-distro-rid.sh +++ b/eng/common/native/init-distro-rid.sh @@ -39,6 +39,8 @@ getNonPortableDistroRid() # $rootfsDir can be empty. freebsd-version is a shell script and should always work. __freebsd_major_version=$("$rootfsDir"/bin/freebsd-version | cut -d'.' -f1) nonPortableRid="freebsd.$__freebsd_major_version-${targetArch}" + elif [ "$targetOs" = "openbsd" ]; then + nonPortableRid="openbsd.$(uname -r)-${targetArch}" elif command -v getprop >/dev/null && getprop ro.product.system.model | grep -qi android; then __android_sdk_version=$(getprop ro.build.version.sdk) nonPortableRid="android.$__android_sdk_version-${targetArch}" diff --git a/eng/common/native/install-dependencies.sh b/eng/common/native/install-dependencies.sh index 477a44f335b..aff839fa097 100644 --- a/eng/common/native/install-dependencies.sh +++ b/eng/common/native/install-dependencies.sh @@ -24,14 +24,16 @@ case "$os" in apt update apt install -y build-essential gettext locales cmake llvm clang lld lldb liblldb-dev libunwind8-dev libicu-dev liblttng-ust-dev \ - libssl-dev libkrb5-dev pigz cpio + libssl-dev libkrb5-dev pigz cpio ninja-build file localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8 - elif [ "$ID" = "fedora" ] || [ "$ID" = "rhel" ] || [ "$ID" = "azurelinux" ]; then + elif [ "$ID" = "fedora" ] || [ "$ID" = "rhel" ] || [ "$ID" = "azurelinux" ] || [ "$ID" = "centos" ]; then pkg_mgr="$(command -v tdnf 2>/dev/null || command -v dnf)" - $pkg_mgr install -y cmake llvm lld lldb clang python curl libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio + $pkg_mgr install -y cmake llvm lld lldb clang python curl libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build file + elif [ "$ID" = "amzn" ]; then + dnf install -y cmake llvm lld lldb clang python libicu-devel openssl-devel krb5-devel lttng-ust-devel pigz cpio ninja-build file elif [ "$ID" = "alpine" ]; then - apk add build-base cmake bash curl clang llvm-dev lld lldb krb5-dev lttng-ust-dev icu-dev openssl-dev pigz cpio + apk add build-base cmake bash curl clang llvm llvm-dev lld lldb-dev krb5-dev lttng-ust-dev icu-dev openssl-dev pigz cpio ninja file else echo "Unsupported distro. distro: $ID" exit 1 @@ -52,6 +54,7 @@ brew "openssl@3" brew "pkgconf" brew "python3" brew "pigz" +brew "ninja" EOF ;; diff --git a/eng/common/templates/vmr-build-pr.yml b/eng/common/templates/vmr-build-pr.yml index 2f3694fa132..d24de935248 100644 --- a/eng/common/templates/vmr-build-pr.yml +++ b/eng/common/templates/vmr-build-pr.yml @@ -33,7 +33,7 @@ resources: - repository: vmr type: github name: dotnet/dotnet - endpoint: dotnet + endpoint: public ref: refs/heads/main # Set to whatever VMR branch the PR build should insert into stages: diff --git a/eng/packages/General.props b/eng/packages/General.props index 59290680f74..5d587eece7c 100644 --- a/eng/packages/General.props +++ b/eng/packages/General.props @@ -17,7 +17,7 @@ - + @@ -41,7 +41,7 @@ - + diff --git a/eng/packages/ProjectTemplates.props b/eng/packages/ProjectTemplates.props index 81380bfdfc8..a7151829917 100644 --- a/eng/packages/ProjectTemplates.props +++ b/eng/packages/ProjectTemplates.props @@ -18,16 +18,19 @@ - - - - - + + + + + + - - - + + + + + diff --git a/eng/packages/Tests.props b/eng/packages/Tests.props index 91c3a92a444..0c9c97cae39 100644 --- a/eng/packages/Tests.props +++ b/eng/packages/Tests.props @@ -15,10 +15,9 @@ - - - - + + + @@ -33,11 +32,8 @@ - - - - - + + @@ -49,7 +45,7 @@ - + diff --git a/eng/xunit.runner.json b/eng/xunit.runner.json index 826972feba6..93a90a659aa 100644 --- a/eng/xunit.runner.json +++ b/eng/xunit.runner.json @@ -1,5 +1,5 @@ { + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", "diagnosticMessages": true, - "longRunningTestSeconds": 300, - "shadowCopy": false + "longRunningTestSeconds": 300 } diff --git a/global.json b/global.json index a08b9da575a..082820d03b1 100644 --- a/global.json +++ b/global.json @@ -1,9 +1,9 @@ { "sdk": { - "version": "10.0.108" + "version": "10.0.109" }, "tools": { - "dotnet": "10.0.108", + "dotnet": "10.0.109", "runtimes": { "dotnet": [ "8.0.0", @@ -20,7 +20,7 @@ "msbuild-sdks": { "Microsoft.Build.NoTargets": "3.7.0", "Microsoft.Build.Traversal": "4.1.82", - "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26275.1", - "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.26275.1" + "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.26324.4", + "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.26324.4" } } diff --git a/scripts/Slngen.ps1 b/scripts/Slngen.ps1 index 1980f458e94..5924fcb03ea 100755 --- a/scripts/Slngen.ps1 +++ b/scripts/Slngen.ps1 @@ -169,10 +169,6 @@ Push-Location $RepositoryPath try { [System.Collections.ArrayList]$Globs = @() - if (!$OnlySources) { - $Globs += "test/TestUtilities/TestUtilities.csproj" - } - if (!$All) { foreach ($Keyword in $Keywords) { $Globs += "src/**/*$($Keyword)*/**/*.*sproj" diff --git a/src/Analyzers/Microsoft.Analyzers.Extra/Utilities/SymbolExtensions.cs b/src/Analyzers/Microsoft.Analyzers.Extra/Utilities/SymbolExtensions.cs index bc8966ba8cf..078ab556cf6 100644 --- a/src/Analyzers/Microsoft.Analyzers.Extra/Utilities/SymbolExtensions.cs +++ b/src/Analyzers/Microsoft.Analyzers.Extra/Utilities/SymbolExtensions.cs @@ -32,7 +32,7 @@ public static bool IsAncestorOf(this ITypeSymbol potentialAncestor, ITypeSymbol } /// - /// True if the symbol is externally visible outside this assembly. + /// Determines whether the symbol is externally visible outside this assembly. /// public static bool IsExternallyVisible(this ISymbol symbol) { diff --git a/src/Analyzers/Microsoft.Analyzers.Local/Utilities/SymbolExtensions.cs b/src/Analyzers/Microsoft.Analyzers.Local/Utilities/SymbolExtensions.cs index f3665b80295..2cefcdfa7af 100644 --- a/src/Analyzers/Microsoft.Analyzers.Local/Utilities/SymbolExtensions.cs +++ b/src/Analyzers/Microsoft.Analyzers.Local/Utilities/SymbolExtensions.cs @@ -8,7 +8,7 @@ namespace Microsoft.Extensions.LocalAnalyzers.Utilities; internal static class SymbolExtensions { /// - /// True if the symbol is externally visible outside this assembly. + /// Determines whether the symbol is externally visible outside this assembly. /// public static bool IsExternallyVisible(this ISymbol symbol) { diff --git a/src/LegacySupport/CompilerFeatureRequiredAttribute/CompilerFeatureRequiredAttribute.cs b/src/LegacySupport/CompilerFeatureRequiredAttribute/CompilerFeatureRequiredAttribute.cs index b979931673c..49a55ac603d 100644 --- a/src/LegacySupport/CompilerFeatureRequiredAttribute/CompilerFeatureRequiredAttribute.cs +++ b/src/LegacySupport/CompilerFeatureRequiredAttribute/CompilerFeatureRequiredAttribute.cs @@ -17,12 +17,12 @@ public CompilerFeatureRequiredAttribute(string featureName) } /// - /// The name of the compiler feature. + /// Gets the name of the compiler feature. /// public string FeatureName { get; } /// - /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + /// Gets a value indicating whether the compiler can choose to allow access to the location where this attribute is applied if it does not understand . /// public bool IsOptional { get; init; } diff --git a/src/LegacySupport/NullabilityInfoContext/NullabilityInfo.cs b/src/LegacySupport/NullabilityInfoContext/NullabilityInfo.cs index bd9b132cd0f..7d989ce128c 100644 --- a/src/LegacySupport/NullabilityInfoContext/NullabilityInfo.cs +++ b/src/LegacySupport/NullabilityInfoContext/NullabilityInfo.cs @@ -25,28 +25,28 @@ internal NullabilityInfo(Type type, NullabilityState readState, NullabilityState } /// - /// The of the member or generic parameter + /// Gets the of the member or generic parameter /// to which this NullabilityInfo belongs. /// public Type Type { get; } /// - /// The nullability read state of the member. + /// Gets the nullability read state of the member. /// public NullabilityState ReadState { get; internal set; } /// - /// The nullability write state of the member. + /// Gets the nullability write state of the member. /// public NullabilityState WriteState { get; internal set; } /// - /// If the member type is an array, gives the of the elements of the array, null otherwise. + /// Gets the of the elements of the array if the member type is an array; otherwise, . /// public NullabilityInfo? ElementType { get; } /// - /// If the member type is a generic type, gives the array of for each type parameter. + /// Gets the array of values for each type parameter if the member type is a generic type. /// public NullabilityInfo[] GenericTypeArguments { get; } } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatToolMode.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatToolMode.cs index 73134a5d894..9fef5e2d37f 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatToolMode.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/ChatCompletion/ChatToolMode.cs @@ -49,8 +49,11 @@ private protected ChatToolMode() /// /// Gets a predefined indicating that tool usage is required, - /// but that any tool can be selected. At least one tool must be provided in . + /// but that any tool can be selected. /// + /// + /// At least one tool must be provided in . + /// public static RequiredChatToolMode RequireAny { get; } = new(requiredFunctionName: null); /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalRequestContent.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalRequestContent.cs index da5e75d49a8..7295a04b09c 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalRequestContent.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalRequestContent.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; +using Microsoft.Shared.DiagnosticIds; using Microsoft.Shared.Diagnostics; namespace Microsoft.Extensions.AI; @@ -32,6 +34,21 @@ public ToolApprovalRequestContent(string requestId, ToolCallContent toolCall) /// public ToolCallContent ToolCall { get; } + /// + /// Gets or sets a value indicating whether the underlying tool call must be confirmed + /// before it is invoked. + /// + /// + /// Defaults to . When , the underlying tool + /// requires a confirmation (such as a user prompt, a policy decision, or any other approver) + /// before it can be invoked. When , the underlying tool does not + /// require a confirmation and the consumer may proceed without prompting; a corresponding + /// still has to be supplied so the originating + /// tool call can be invoked. + /// + [Experimental(DiagnosticIds.Experiments.AIApprovalsInvocationRequired, UrlFormat = DiagnosticIds.UrlFormat)] + public bool RequiresConfirmation { get; set; } = true; + /// /// Creates a indicating whether the tool call is approved or rejected. /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactory.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactory.cs index 4625b168aa6..803e80ea8dd 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactory.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactory.cs @@ -135,7 +135,8 @@ public static AIFunction Create(Delegate method, AIFunctionFactoryOptions? optio /// The method to be represented via the created . /// /// The name to use for the . If , the name will be derived from - /// any on , if available, or else from the name of . + /// any on , then from any + /// on , if available, or else from the name of . /// /// /// The description to use for the . If , a description will be derived from @@ -313,7 +314,8 @@ public static AIFunction Create(MethodInfo method, object? target, AIFunctionFac /// /// /// The name to use for the . If , the name will be derived from - /// any on , if available, or else from the name of . + /// any on , then from any + /// on , if available, or else from the name of . /// /// /// The description to use for the . If , a description will be derived from @@ -708,7 +710,7 @@ private sealed class ReflectionAIFunctionDescriptor private static readonly object? _boxedDefaultCancellationToken = default(CancellationToken); /// - /// Gets or creates a descriptors using the specified method and options. + /// Gets or creates a descriptor using the specified method and options. /// public static ReflectionAIFunctionDescriptor GetOrCreate(MethodInfo method, AIFunctionFactoryOptions options) { @@ -806,7 +808,11 @@ private ReflectionAIFunctionDescriptor(DescriptorKey key, JsonSerializerOptions pType != typeof(IServiceProvider) && !string.IsNullOrEmpty(parameters[i].Name)) { - _ = expectedArgumentNames.Add(parameters[i].Name!); + string effectiveName = AIJsonUtilities.GetParameterSchemaName(parameters[i]); + if (!expectedArgumentNames.Add(effectiveName)) + { + Throw.ArgumentException("method", $"Multiple parameters are mapped to the same name '{effectiveName}'. Ensure that any {nameof(AIParameterNameAttribute)} values do not collide with each other or with other parameter names."); + } } } @@ -815,7 +821,7 @@ private ReflectionAIFunctionDescriptor(DescriptorKey key, JsonSerializerOptions ReturnParameterMarshaller = GetReturnParameterMarshaller(key, serializerOptions, out Type? returnType); Method = key.Method; - Name = key.Name ?? key.Method.GetCustomAttribute(inherit: true)?.DisplayName ?? GetFunctionName(key.Method); + Name = key.Name ?? key.Method.GetCustomAttribute(inherit: true)?.Name ?? key.Method.GetCustomAttribute(inherit: true)?.DisplayName ?? GetFunctionName(key.Method); Description = key.Description ?? key.Method.GetCustomAttribute(inherit: true)?.Description ?? string.Empty; JsonSerializerOptions = serializerOptions; ReturnJsonSchema = returnType is null || key.ExcludeResultSchema ? null : AIJsonUtilities.CreateJsonSchema( @@ -949,10 +955,11 @@ static bool IsAsyncMethod(MethodInfo method) // Resolve the contract used to marshal the value from JSON -- can throw if not supported or not found. JsonTypeInfo? typeInfo = serializerOptions.GetTypeInfo(parameterType); bool hasDefaultValue = AIJsonUtilities.TryGetEffectiveDefaultValue(parameter, out object? effectiveDefaultValue); + string argumentName = AIJsonUtilities.GetParameterSchemaName(parameter); return (arguments, _) => { // If the parameter has an argument specified in the dictionary, return that argument. - if (arguments.TryGetValue(parameter.Name, out object? value)) + if (arguments.TryGetValue(argumentName, out object? value)) { return value switch { @@ -999,7 +1006,7 @@ static bool IsAsyncMethod(MethodInfo method) // If the parameter is required and there's no argument specified for it, throw. if (!hasDefaultValue) { - Throw.ArgumentException(nameof(arguments), $"The arguments dictionary is missing a value for the required parameter '{parameter.Name}'."); + Throw.ArgumentException(nameof(arguments), $"The arguments dictionary is missing a value for the required parameter '{argumentName}'."); } // Otherwise, use the optional parameter's default value. @@ -1217,9 +1224,11 @@ private static bool IsAIContentRelatedType(Type type) => { return method.ReturnParameter.GetCustomAttribute(inherit: true)?.Description; } - catch (Exception e) when (e is ArgumentNullException or NullReferenceException) + catch (Exception e) when (e is ArgumentNullException or NullReferenceException or IndexOutOfRangeException) { - // DynamicMethod return parameters don't support GetCustomAttribute. + // DynamicMethod return parameters don't support GetCustomAttribute. Additionally, on .NET Framework, + // querying inherited attributes on the return parameter of an overriding method can throw + // IndexOutOfRangeException. In either case, treat the description as absent. return null; } } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactoryOptions.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactoryOptions.cs index 094bb09337a..ff80e6978ed 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactoryOptions.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactoryOptions.cs @@ -50,7 +50,7 @@ public AIFunctionFactoryOptions() /// Gets or sets the name to use for the function. /// - /// The name to use for the function. The default value is a name derived from the passed or (for example, via a on the method). + /// The name to use for the function. The default value is a name derived from the passed or (for example, via an or on the method). /// public string? Name { get; set; } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionNameAttribute.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionNameAttribute.cs new file mode 100644 index 00000000000..6eb0ba15d42 --- /dev/null +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionNameAttribute.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; +using Microsoft.Shared.Diagnostics; + +namespace Microsoft.Extensions.AI; + +/// Specifies the name to use for an . +/// +/// The name is the identifier a model sees and uses to invoke a function. +/// By default this is inferred from .NET metadata. Apply this attribute to use a different identifier. +/// +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +[Experimental(DiagnosticIds.Experiments.AIFunctionAndParameterName, UrlFormat = DiagnosticIds.UrlFormat)] +public sealed class AIFunctionNameAttribute : Attribute +{ + /// Initializes a new instance of the class. + /// The name to use for the function. + /// is . + /// is empty or composed entirely of whitespace. + public AIFunctionNameAttribute(string name) + { + Name = Throw.IfNullOrWhitespace(name); + } + + /// Gets the name to use for the function. + public string Name { get; } +} diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIParameterNameAttribute.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIParameterNameAttribute.cs new file mode 100644 index 00000000000..2550b779c03 --- /dev/null +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIParameterNameAttribute.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Shared.DiagnosticIds; +using Microsoft.Shared.Diagnostics; + +namespace Microsoft.Extensions.AI; + +/// Specifies the schema name to use for an parameter. +/// +/// The name is the identifier a model sees and uses when supplying an argument to a function. +/// By default this is inferred from .NET metadata. Apply this attribute to use a different identifier. +/// +[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)] +[Experimental(DiagnosticIds.Experiments.AIFunctionAndParameterName, UrlFormat = DiagnosticIds.UrlFormat)] +public sealed class AIParameterNameAttribute : Attribute +{ + /// Initializes a new instance of the class. + /// The schema name to use for the parameter. + /// is . + /// is empty or composed entirely of whitespace. + public AIParameterNameAttribute(string name) + { + Name = Throw.IfNullOrWhitespace(name); + } + + /// Gets the schema name to use for the parameter. + public string Name { get; } +} diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json index f48b3048be7..dc4542d4ae7 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json @@ -1,5 +1,5 @@ { - "Name": "Microsoft.Extensions.AI.Abstractions, Version=10.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", + "Name": "Microsoft.Extensions.AI.Abstractions, Version=10.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", "Types": [ { "Type": "sealed class Microsoft.Extensions.AI.AdditionalPropertiesDictionary : Microsoft.Extensions.AI.AdditionalPropertiesDictionary", @@ -417,6 +417,38 @@ } ] }, + { + "Type": "sealed class Microsoft.Extensions.AI.AIFunctionNameAttribute : System.Attribute", + "Stage": "Experimental", + "Methods": [ + { + "Member": "Microsoft.Extensions.AI.AIFunctionNameAttribute.AIFunctionNameAttribute(string name);", + "Stage": "Experimental" + } + ], + "Properties": [ + { + "Member": "string Microsoft.Extensions.AI.AIFunctionNameAttribute.Name { get; }", + "Stage": "Experimental" + } + ] + }, + { + "Type": "sealed class Microsoft.Extensions.AI.AIParameterNameAttribute : System.Attribute", + "Stage": "Experimental", + "Methods": [ + { + "Member": "Microsoft.Extensions.AI.AIParameterNameAttribute.AIParameterNameAttribute(string name);", + "Stage": "Experimental" + } + ], + "Properties": [ + { + "Member": "string Microsoft.Extensions.AI.AIParameterNameAttribute.Name { get; }", + "Stage": "Experimental" + } + ] + }, { "Type": "readonly struct Microsoft.Extensions.AI.AIJsonSchemaCreateContext", "Stage": "Stable", @@ -4604,6 +4636,10 @@ } ], "Properties": [ + { + "Member": "bool Microsoft.Extensions.AI.ToolApprovalRequestContent.RequiresConfirmation { get; set; }", + "Stage": "Experimental" + }, { "Member": "Microsoft.Extensions.AI.ToolCallContent Microsoft.Extensions.AI.ToolApprovalRequestContent.ToolCall { get; }", "Stage": "Stable" diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeAudioFormat.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeAudioFormat.cs index c8684185268..a8a6e984315 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeAudioFormat.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeAudioFormat.cs @@ -22,12 +22,12 @@ public RealtimeAudioFormat(string mediaType, int sampleRate) } /// - /// Gets the media type of the audio (e.g., "audio/pcm", "audio/pcmu", "audio/pcma"). + /// Gets or initializes the media type of the audio (e.g., "audio/pcm", "audio/pcmu", "audio/pcma"). /// public string MediaType { get; init; } /// - /// Gets the sample rate of the audio in Hertz. + /// Gets or initializes the sample rate of the audio in Hertz. /// public int SampleRate { get; init; } } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeClientMessage.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeClientMessage.cs index 0f035933462..551a425069a 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeClientMessage.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeClientMessage.cs @@ -14,8 +14,10 @@ public class RealtimeClientMessage { /// /// Gets or sets the optional message ID associated with the message. - /// This can be used for tracking and correlation purposes. /// + /// + /// This can be used for tracking and correlation purposes. + /// public string? MessageId { get; set; } /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeConversationItem.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeConversationItem.cs index 7373a5d6773..1af5616b9e7 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeConversationItem.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeConversationItem.cs @@ -55,7 +55,9 @@ public RealtimeConversationItem(IList contents, string? id = null, Ch /// /// Gets or sets the raw representation of the conversation item. - /// This can be used to hold the original data structure received from or sent to the provider. /// + /// + /// This can be used to hold the original data structure received from or sent to the provider. + /// public object? RawRepresentation { get; set; } } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeServerMessage.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeServerMessage.cs index 0e023fde4f4..eeeacce761f 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeServerMessage.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeServerMessage.cs @@ -19,8 +19,10 @@ public class RealtimeServerMessage /// /// Gets or sets the optional message ID associated with the response. - /// This can be used for tracking and correlation purposes. /// + /// + /// This can be used for tracking and correlation purposes. + /// public string? MessageId { get; set; } /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeSessionOptions.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeSessionOptions.cs index 61326c517bd..2e32c93cd95 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeSessionOptions.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/RealtimeSessionOptions.cs @@ -22,58 +22,60 @@ public class RealtimeSessionOptions public RealtimeSessionKind SessionKind { get; init; } = RealtimeSessionKind.Conversation; /// - /// Gets the model name to use for the session. + /// Gets or initializes the model name to use for the session. /// public string? Model { get; init; } /// - /// Gets the input audio format for the session. + /// Gets or initializes the input audio format for the session. /// public RealtimeAudioFormat? InputAudioFormat { get; init; } /// - /// Gets the transcription options for the session. + /// Gets or initializes the transcription options for the session. /// public TranscriptionOptions? TranscriptionOptions { get; init; } /// - /// Gets the output audio format for the session. + /// Gets or initializes the output audio format for the session. /// public RealtimeAudioFormat? OutputAudioFormat { get; init; } /// - /// Gets the output voice for the session. + /// Gets or initializes the output voice for the session. /// public string? Voice { get; init; } /// - /// Gets the default system instructions for the session. + /// Gets or initializes the default system instructions for the session. /// public string? Instructions { get; init; } /// - /// Gets the maximum number of response tokens for the session. + /// Gets or initializes the maximum number of response tokens for the session. /// public int? MaxOutputTokens { get; init; } /// - /// Gets the output modalities for the response. like "text", "audio". - /// If null, then default conversation modalities will be used. + /// Gets or initializes the output modalities for the response, for example, "text" and "audio". /// + /// + /// If , the default conversation modalities are used. + /// public IReadOnlyList? OutputModalities { get; init; } /// - /// Gets the tool choice mode for the session. + /// Gets or initializes the tool choice mode for the session. /// public ChatToolMode? ToolMode { get; init; } /// - /// Gets the AI tools available for generating the response. + /// Gets or initializes the AI tools available for generating the response. /// public IReadOnlyList? Tools { get; init; } /// - /// Gets the voice activity detection (VAD) options for the session. + /// Gets or initializes the voice activity detection (VAD) options for the session. /// /// /// When set, configures how the server detects user speech to manage turn-taking. diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/ResponseCreatedRealtimeServerMessage.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/ResponseCreatedRealtimeServerMessage.cs index 517b9f8dc04..d09c7dd4b96 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/ResponseCreatedRealtimeServerMessage.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Realtime/ResponseCreatedRealtimeServerMessage.cs @@ -41,8 +41,11 @@ public ResponseCreatedRealtimeServerMessage(RealtimeServerMessageType type) } /// - /// Gets or sets the output audio options for the response. If null, the default conversation audio options will be used. + /// Gets or sets the output audio options for the response. /// + /// + /// If , the default conversation audio options are used. + /// public RealtimeAudioFormat? OutputAudioOptions { get; set; } /// @@ -85,9 +88,12 @@ public ResponseCreatedRealtimeServerMessage(RealtimeServerMessageType type) public IList? Items { get; set; } /// - /// Gets or sets the output modalities for the response. like "text", "audio". - /// If null, then default conversation modalities will be used. + /// Gets or sets the output modalities for the response. + /// For example, "text" and "audio". /// + /// + /// If , the default conversation modalities are used. + /// public IList? OutputModalities { get; set; } /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs index d96698776db..853b0e79ddd 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedMcpServerTool.cs @@ -94,8 +94,11 @@ private static string ValidateUrl(Uri serverAddress) public string ServerName { get; } /// - /// Gets the address of the remote MCP server. This may be a URL, or in the case of a service providing built-in MCP servers with known names, it can be such a name. + /// Gets the address of the remote MCP server. /// + /// + /// This may be a URL. For a service providing built-in MCP servers with known names, it can instead be such a name. + /// public string ServerAddress { get; } /// diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaCreateOptions.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaCreateOptions.cs index 6a65e802dd3..468f59aa784 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaCreateOptions.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaCreateOptions.cs @@ -20,7 +20,7 @@ public sealed record class AIJsonSchemaCreateOptions public static AIJsonSchemaCreateOptions Default { get; } = new AIJsonSchemaCreateOptions(); /// - /// Gets a callback that is invoked for every schema that is generated within the type graph. + /// Gets or initializes a callback that is invoked for every schema that is generated within the type graph. /// public Func? TransformSchemaNode { get; init; } @@ -49,7 +49,7 @@ public sealed record class AIJsonSchemaCreateOptions public Func? ParameterDescriptionProvider { get; init; } /// - /// Gets a governing transformations on the JSON schema after it has been generated. + /// Gets or initializes a governing transformations on the JSON schema after it has been generated. /// public AIJsonSchemaTransformOptions? TransformOptions { get; init; } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformContext.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformContext.cs index 4cfd08e160b..7f4b03262e6 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformContext.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformContext.cs @@ -11,7 +11,7 @@ namespace Microsoft.Extensions.AI; /// Defines the context for transforming a schema node withing a larger schema document. /// /// -/// This struct is being passed to the user-provided +/// This struct is being passed to the user-provided /// callback by the method and cannot be instantiated directly. /// public readonly struct AIJsonSchemaTransformContext diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformOptions.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformOptions.cs index 101cfa03168..54269f8c040 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformOptions.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonSchemaTransformOptions.cs @@ -12,7 +12,7 @@ namespace Microsoft.Extensions.AI; public sealed record class AIJsonSchemaTransformOptions { /// - /// Gets a callback that is invoked for every schema that is generated within the type graph. + /// Gets or initializes a callback that is invoked for every schema that is generated within the type graph. /// public Func? TransformSchemaNode { get; init; } diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs index c7d2a34f005..9913c33a18f 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs @@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; +using System.Text; using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Schema; @@ -128,14 +129,20 @@ public static JsonElement CreateFunctionJsonSchema( serializerOptions, inferenceOptions); - parameterSchemas.Add(parameter.Name, parameterSchema); + string parameterSchemaName = GetParameterSchemaName(parameter); + if (parameterSchemas.ContainsKey(parameterSchemaName)) + { + Throw.ArgumentException(nameof(method), $"Multiple parameters are mapped to the same name '{parameterSchemaName}'. Ensure that any {nameof(AIParameterNameAttribute)} values do not collide with each other or with other parameter names."); + } + + parameterSchemas.Add(parameterSchemaName, parameterSchema); bool isRequired = !parameter.IsOptional && !hasDefaultValue; #if NET || NETFRAMEWORK isRequired = isRequired || parameter.GetCustomAttribute(inherit: true) is not null; #endif if (isRequired) { - (requiredProperties ??= []).Add((JsonNode)parameter.Name); + (requiredProperties ??= []).Add((JsonNode)parameterSchemaName); } } @@ -282,12 +289,14 @@ JsonNode TransformSchemaNode(JsonSchemaExporterContext schemaExporterContext, Js // to accommodate the fact that they're being nested inside of a higher-level schema. if (parameter?.Name is not null && objSchema.TryGetPropertyValue(RefPropertyName, out JsonNode? paramName)) { - // Fix up any $ref URIs to match the path from the root document. + // Fix up any $ref URIs to match the path from the root document. The schema name becomes a + // JSON Pointer segment, so escape it per RFC 6901 ('~' => "~0", '/' => "~1"). + string parameterSchemaName = EscapeJsonPointerSegment(GetParameterSchemaName(parameter)); string refUri = paramName!.GetValue(); Debug.Assert(refUri is "#" || refUri.StartsWith("#/", StringComparison.Ordinal), $"Expected {nameof(refUri)} to be either # or start with #/, got {refUri}"); refUri = refUri == "#" - ? $"#/{PropertiesPropertyName}/{parameter.Name}" - : $"#/{PropertiesPropertyName}/{parameter.Name}/{refUri.AsMemory("#/".Length)}"; + ? $"#/{PropertiesPropertyName}/{parameterSchemaName}" + : $"#/{PropertiesPropertyName}/{parameterSchemaName}/{refUri.AsMemory("#/".Length)}"; objSchema[RefPropertyName] = (JsonNode)refUri; } @@ -861,6 +870,30 @@ internal static bool TryGetEffectiveDefaultValue(ParameterInfo parameterInfo, ou return false; } + internal static string GetParameterSchemaName(ParameterInfo parameter) => + parameter.GetCustomAttribute(inherit: true)?.Name ?? parameter.Name!; + + private static string EscapeJsonPointerSegment(string segment) + { + if (segment.IndexOfAny(['~', '/']) < 0) + { + return segment; + } + + StringBuilder sb = new(segment.Length + 2); + foreach (char c in segment) + { + _ = c switch + { + '~' => sb.Append("~0"), + '/' => sb.Append("~1"), + _ => sb.Append(c), + }; + } + + return sb.ToString(); + } + /// /// Checks whether a parameter is an F# optional parameter declared with the ?param syntax. /// F# optional parameters are annotated with Microsoft.FSharp.Core.OptionalArgumentAttribute diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Console/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Console/README.md index dfc15311489..166841f72f3 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Console/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Console/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.NLP/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.NLP/README.md index dfc15311489..166841f72f3 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.NLP/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.NLP/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Quality/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Quality/README.md index dfc15311489..166841f72f3 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Quality/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Quality/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Microsoft.Extensions.AI.Evaluation.Reporting.Azure.csproj b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Microsoft.Extensions.AI.Evaluation.Reporting.Azure.csproj index ddc986f187a..c7e88cbb236 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Microsoft.Extensions.AI.Evaluation.Reporting.Azure.csproj +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/Microsoft.Extensions.AI.Evaluation.Reporting.Azure.csproj @@ -12,6 +12,7 @@ true n/a n/a + $(NoWarn);MEAI001 diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/README.md index dfc15311489..166841f72f3 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Azure/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Microsoft.Extensions.AI.Evaluation.Reporting.csproj b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Microsoft.Extensions.AI.Evaluation.Reporting.csproj index 8a960fc4df1..331e7466a15 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Microsoft.Extensions.AI.Evaluation.Reporting.csproj +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/Microsoft.Extensions.AI.Evaluation.Reporting.csproj @@ -19,6 +19,7 @@ true n/a n/a + $(NoWarn);MEAI001 diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/README.md index dfc15311489..166841f72f3 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/CSharp/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/azure-devops-report/overview.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/azure-devops-report/overview.md index 04c4d5a6c96..90ba8128fa2 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/azure-devops-report/overview.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/azure-devops-report/overview.md @@ -12,7 +12,7 @@ This extension publishes a `PublishAIEvaluationReport` task that will publish th - task: PublishAIEvaluationReport@0 displayName: 'Publish AI Evaluation Data' inputs: - reportFile: '$(build-artifacts)\report.json' + reportFile: '$(build-artifacts)\report.json' ``` If your pipeline restricts uploading attachments from a task, you can disable the attachment upload feature and use a different method to upload the report data. You should still include `PublishAIEvaluationReport` task as it will trigger the display of the reporting tab. When using this method, the attachment must be uploaded to the pipeline with `type=ai-eval-report-json` and `name=ai-eval-report`. @@ -68,10 +68,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package-lock.json b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package-lock.json index b31088194d7..06f7af047fe 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package-lock.json +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package-lock.json @@ -23,7 +23,7 @@ "@types/node": "^22.5.3", "@types/react": "^18.3.19", "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", + "@vitejs/plugin-react": "^6.0.2", "babel-plugin-transform-amd-to-commonjs": "^1.6.0", "eslint": "^9.9.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0", @@ -33,18 +33,19 @@ "tfx-cli": "^0.21.0", "typescript": "^5.5.3", "typescript-eslint": "^8.27.0", - "vite": "^6.4.2", + "vite": "^8.0.16", "vite-plugin-singlefile": "^2.0.2" } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha1-fNelnxWzzA3NgDA493knEqfQsVw=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha1-8vu/6ofESiFZDsUVt3iywm2IZuc=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -53,31 +54,33 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha1-ANA+jArCTdm+lCxTcJkMvh8X2I0=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha1-bwI38PNtLlHAVwpjb67Z0tDv5ik=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha1-UoateF33951lbojOhuZQ0Wyl8yI=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha1-gMELFySAgpaLV6hXuRZAlx8gcPc=", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -94,14 +97,15 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha1-0Jh2KQERq7sA75Yqe4OlMH+6DVA=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha1-zKC4gn5rzzuhdniOfzsYCtbbL6M=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -111,14 +115,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha1-MsSj9B8S7RUyF5sQik10bhBcKyU=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha1-eh3vcEMCQBxH9k+oVYnpdK4hcEI=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -128,39 +133,42 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha1-uUMN8qpOF7woZl6t6uiqHZheZnQ=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha1-8EqW+9hHMkGxB5JD9bPwOjAQq3s=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha1-YGMsvW/7cLIoIxhyARFnYqA+LVw=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha1-7yUEilGOgo1zk/rFiC3dc5Idc5Y=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha1-kxLZ2eVu3DWutulcJdQQa1C56x4=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha1-sGJ0elmXuhOGNyATKLv/d5YFdK4=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -169,68 +177,63 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", - "integrity": "sha1-bxPqJRtoyFMumF/VMvKHQaivmsg=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha1-VNp5YJerGc5n7Z+ItHuy7Ek2doc=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha1-fwhx2Zgk0jE31g+G/PYTD9WhtR8=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha1-AQtpOPq3y333SqK7wGqlA7j+X7Q=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha1-vYcITO0MeW7Ea9pJLeboPSnon8I=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha1-+lL1sefbGrBJRFtCHERxMDiXcC8=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha1-zzFb6UAhOzVOtKvMC9Aevj9zvCo=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha1-nPvMsCuOIpiSwLBwOAUswahwnEk=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha1-Rav951SJl+NDdsPmn+tHXP+0pgc=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha1-WL1QuaeVHRNJiKGuF3o175pwO6E=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha1-g3uHOHy/XsVTDLY0s8Yi9o7bkzQ=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -239,75 +242,45 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha1-r2eNhQas9SxXfKxz/3/mYVyF/JI=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha1-3P4sJAlLt1e/c5YDdOfFXkNPGfA=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha1-mm4tBfS2aS4YAc1PsXatgjkw7V4=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha1-EgIkUMRaTabY2Ch7GKT/Ldsj92g=", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha1-Dn5W7O23iu72bOeXKwgvznaiPlc=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha1-TZ1ABPZFzdME3pWMclFieE7KxwA=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha1-8yPQUAFEAlPurTychYrb4AuQMQo=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha1-xHsHpBuV2gkH0Ca13YlNmN59Ly0=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -315,14 +288,15 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha1-n1seg4xEbnLPPNS5GBUrjGBeN8c=", + "version": "7.29.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha1-gAXjHYJxLuetrvbiPGO3GmJ3CpI=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -347,453 +321,45 @@ "node": ">=10" } }, - "node_modules/@emotion/hash": { - "version": "0.9.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@emotion/hash/-/hash-0.9.2.tgz", - "integrity": "sha1-/5IhufWLTf5h5hmneIc0vWP2iYs=", - "license": "MIT" - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha1-gPy+NhMOWLdnBRHoiLjoiiWe12w=", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha1-MAcSEB9/UPHSYnoWLm4JsQm2dno=", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha1-iqSWX40KeYLcIXNL9mATI6Ztp1I=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha1-h9+ycWEgK9yVjvSLthsJx1j67hY=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha1-eRl4mOwf90XSHAceHHzDyALwwf0=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha1-FGQAqFYhM/RcTS6tzzfd0JcYB54=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha1-HF+bpyBuFY/SskxZ+i0si7R8oP4=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha1-6mMfSja+qsS5J5+g/MbKKerusrM=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha1-RSzWayCTLQi9xTqLYcDjC69DSLk=", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha1-4QZrzlg5TxsRQd7shVel8KIvWXc=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha1-sk+KzEW89UGSx/LzvhtT5lUer+A=", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha1-+c//p/yDIlcfvEyLMmjK8VvYGtA=", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha1-V1oUvXRkT/q4ka3H1+YNJ1KW8s0=", - "cpu": [ - "mips64el" - ], + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha1-OAzMjyQS6iLR2XLff47iOjucdGc=", "dev": true, "license": "MIT", "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha1-dbmccKlfvV93OddpK+/mBgFZGGk=", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha1-LjJZRAMhpE553fdTXDJQV9qHXNY=", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha1-F2dsq7/lko2lsqDW311YzQjbJmM=", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha1-BYN3VoXKggZtBMNQfwlSTTzXowY=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha1-8ExAScsuJS/paxb+2Q9wdGsT9KQ=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha1-d9oNCg2CbXySHuo9QCklSLJYoHY=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha1-Ypb1hnrt7yioGyKrIAnHhqlS3M0=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha1-+NIzAzYOJ7Fs8GWyO7/0PBQUJnk=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha1-SeC3aHRKOSS+DX/ZfdbOmykj2I0=", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha1-pu19Z3jWflKMgfsWWyP0kRubE9Y=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha1-msFMN44bZTrxfQjn0840yu9YcyM=", - "cpu": [ - "arm64" - ], + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha1-SyYMDTU0IE6YxhELjbGph9JuyHw=", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha1-kYlC3LuzXMFPyjmvuRteaj0Scmc=", - "cpu": [ - "ia32" - ], + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha1-KP7SGhuhznl8RKBwq8lNQvOuhUg=", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha1-m9rYF2vngRrRSNH4dyNZBB9GxsU=", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha1-/5IhufWLTf5h5hmneIc0vWP2iYs=", + "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", @@ -1007,26 +573,26 @@ } }, "node_modules/@fluentui/font-icons-mdl2": { - "version": "8.5.72", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.72.tgz", - "integrity": "sha1-Fgpv0KYXz1eJukMj4D+DB68XbQk=", + "version": "8.5.73", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/font-icons-mdl2/-/font-icons-mdl2-8.5.73.tgz", + "integrity": "sha1-0WIeWlNQUgB/O76neNVxfLhPkVw=", "license": "MIT", "dependencies": { "@fluentui/set-version": "^8.2.24", - "@fluentui/style-utilities": "^8.15.0", + "@fluentui/style-utilities": "^8.15.1", "@fluentui/utilities": "^8.17.2", "tslib": "^2.1.0" } }, "node_modules/@fluentui/foundation-legacy": { - "version": "8.6.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/foundation-legacy/-/foundation-legacy-8.6.5.tgz", - "integrity": "sha1-TvM5VF53Cp933y99+NDx0J4Bgh0=", + "version": "8.6.6", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/foundation-legacy/-/foundation-legacy-8.6.6.tgz", + "integrity": "sha1-u4etUWADhmUACX7+Lu36QF4Vo9g=", "license": "MIT", "dependencies": { "@fluentui/merge-styles": "^8.6.14", "@fluentui/set-version": "^8.2.24", - "@fluentui/style-utilities": "^8.15.0", + "@fluentui/style-utilities": "^8.15.1", "@fluentui/utilities": "^8.17.2", "tslib": "^2.1.0" }, @@ -1073,21 +639,21 @@ } }, "node_modules/@fluentui/react": { - "version": "8.125.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react/-/react-8.125.5.tgz", - "integrity": "sha1-4eVl0fBK3a2aloD96BcKbvZd2A8=", + "version": "8.125.6", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react/-/react-8.125.6.tgz", + "integrity": "sha1-xR4vMwXHXYIUF6lDw4Xs42M0iE4=", "license": "MIT", "dependencies": { "@fluentui/date-time-utilities": "^8.6.11", - "@fluentui/font-icons-mdl2": "^8.5.72", - "@fluentui/foundation-legacy": "^8.6.5", + "@fluentui/font-icons-mdl2": "^8.5.73", + "@fluentui/foundation-legacy": "^8.6.6", "@fluentui/merge-styles": "^8.6.14", - "@fluentui/react-focus": "^8.10.5", + "@fluentui/react-focus": "^8.10.6", "@fluentui/react-hooks": "^8.10.2", "@fluentui/react-portal-compat-context": "^9.0.15", "@fluentui/react-window-provider": "^2.3.2", "@fluentui/set-version": "^8.2.24", - "@fluentui/style-utilities": "^8.15.0", + "@fluentui/style-utilities": "^8.15.1", "@fluentui/theme": "^2.7.2", "@fluentui/utilities": "^8.17.2", "@microsoft/load-themed-styles": "^1.10.26", @@ -1101,21 +667,21 @@ } }, "node_modules/@fluentui/react-accordion": { - "version": "9.10.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-accordion/-/react-accordion-9.10.0.tgz", - "integrity": "sha1-IcjQXvP5jzx+Pe280D7tEjNmLiE=", + "version": "9.12.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-accordion/-/react-accordion-9.12.0.tgz", + "integrity": "sha1-V3bCYnIwTKvqp5ArIGlJ5L0wkz8=", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1127,18 +693,18 @@ } }, "node_modules/@fluentui/react-alert": { - "version": "9.0.0-beta.138", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-alert/-/react-alert-9.0.0-beta.138.tgz", - "integrity": "sha1-oJcZOLUoitixfD20mM4W+baE9Y8=", + "version": "9.0.0-beta.140", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-alert/-/react-alert-9.0.0-beta.140.tgz", + "integrity": "sha1-w/TR3Lj23vOUprERUdkGBW5oDWs=", "license": "MIT", "dependencies": { - "@fluentui/react-avatar": "^9.11.0", - "@fluentui/react-button": "^9.9.0", + "@fluentui/react-avatar": "^9.11.2", + "@fluentui/react-button": "^9.9.2", "@fluentui/react-icons": "^2.0.239", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1150,16 +716,16 @@ } }, "node_modules/@fluentui/react-aria": { - "version": "9.17.10", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-aria/-/react-aria-9.17.10.tgz", - "integrity": "sha1-hNTdjzW8+6MWnKMta/HhZsZnlDk=", + "version": "9.17.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-aria/-/react-aria-9.17.12.tgz", + "integrity": "sha1-ThC7uk1wMZ5zAj/E8YbOg/KBPnU=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-tabster": "^9.26.15", + "@fluentui/react-utilities": "^9.26.4", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1170,21 +736,21 @@ } }, "node_modules/@fluentui/react-avatar": { - "version": "9.11.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-avatar/-/react-avatar-9.11.0.tgz", - "integrity": "sha1-aWD/NiyS7z5h45vKyCVmiUfgjF0=", + "version": "9.11.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-avatar/-/react-avatar-9.11.2.tgz", + "integrity": "sha1-Uf8EKERz6ri8sEaozq0yoo+0aTA=", "license": "MIT", "dependencies": { - "@fluentui/react-badge": "^9.5.1", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-badge": "^9.5.3", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-popover": "^9.14.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-popover": "^9.14.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-tooltip": "^9.10.0", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-tooltip": "^9.10.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1196,16 +762,16 @@ } }, "node_modules/@fluentui/react-badge": { - "version": "9.5.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-badge/-/react-badge-9.5.1.tgz", - "integrity": "sha1-nJ3D24wbLDSbHhU0EONyGP5z3nY=", + "version": "9.5.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-badge/-/react-badge-9.5.3.tgz", + "integrity": "sha1-Wm6tS6GUAy4jcUjXlBMNGWAS3OM=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1217,20 +783,20 @@ } }, "node_modules/@fluentui/react-breadcrumb": { - "version": "9.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-breadcrumb/-/react-breadcrumb-9.4.0.tgz", - "integrity": "sha1-J27sIMpFuAZd/AcFGDQRteVnGG0=", + "version": "9.4.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-breadcrumb/-/react-breadcrumb-9.4.2.tgz", + "integrity": "sha1-Cydvp6zZN3foy+gyZBOLCduYb70=", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-button": "^9.9.0", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-button": "^9.9.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-link": "^9.8.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-link": "^9.8.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1242,19 +808,19 @@ } }, "node_modules/@fluentui/react-button": { - "version": "9.9.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-button/-/react-button-9.9.0.tgz", - "integrity": "sha1-RhqlnDCR0/Asz+gXr5hiFNWo/pc=", + "version": "9.9.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-button/-/react-button-9.9.2.tgz", + "integrity": "sha1-6/A/z9A2wmcSrCdsgaY4l2+oUoQ=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", + "@fluentui/react-aria": "^9.17.12", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1266,18 +832,18 @@ } }, "node_modules/@fluentui/react-card": { - "version": "9.6.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-card/-/react-card-9.6.0.tgz", - "integrity": "sha1-HRc7HQLgn5eXncqhcjuVSHZ3fkE=", + "version": "9.7.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-card/-/react-card-9.7.0.tgz", + "integrity": "sha1-m3zgI+sBld2fJonE+N9zTvNYFWA=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", - "@fluentui/react-text": "^9.6.15", + "@fluentui/react-tabster": "^9.26.15", + "@fluentui/react-text": "^9.6.17", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1289,21 +855,21 @@ } }, "node_modules/@fluentui/react-carousel": { - "version": "9.9.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-carousel/-/react-carousel-9.9.6.tgz", - "integrity": "sha1-swR0bwxLli/kT7I8soJZmeR/ue8=", + "version": "9.9.8", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-carousel/-/react-carousel-9.9.8.tgz", + "integrity": "sha1-Ccrje+bXDdtNBsnmg3UQcKY4FJ0=", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-tooltip": "^9.10.0", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-tooltip": "^9.10.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1", "embla-carousel": "^8.5.1", @@ -1318,19 +884,19 @@ } }, "node_modules/@fluentui/react-checkbox": { - "version": "9.6.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-checkbox/-/react-checkbox-9.6.0.tgz", - "integrity": "sha1-HM37dK8vLp/8N8vF+sC9kVF4lsY=", + "version": "9.6.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-checkbox/-/react-checkbox-9.6.2.tgz", + "integrity": "sha1-uWVZnMjhLdl0Rjn9cqztu+zyOzY=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1342,18 +908,18 @@ } }, "node_modules/@fluentui/react-color-picker": { - "version": "9.2.15", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-color-picker/-/react-color-picker-9.2.15.tgz", - "integrity": "sha1-bDHp5Cw+QhM7DhP9lkEeyrLWRfI=", + "version": "9.2.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-color-picker/-/react-color-picker-9.2.17.tgz", + "integrity": "sha1-6kXtW4ZfyJ3ONRKjqoE+uyvXckg=", "license": "MIT", "dependencies": { "@ctrl/tinycolor": "^3.3.4", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1365,23 +931,23 @@ } }, "node_modules/@fluentui/react-combobox": { - "version": "9.17.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-combobox/-/react-combobox-9.17.0.tgz", - "integrity": "sha1-KUVadDbwlQJ97Y2Rd9N5KnwWBIU=", + "version": "9.17.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-combobox/-/react-combobox-9.17.2.tgz", + "integrity": "sha1-aaO1La6Wbu5DPVQC2lS7r2VBQLY=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1393,71 +959,71 @@ } }, "node_modules/@fluentui/react-components": { - "version": "9.73.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-components/-/react-components-9.73.7.tgz", - "integrity": "sha1-7v2Epb/qoGY3u7FAsKw4sA3bCWw=", - "license": "MIT", - "dependencies": { - "@fluentui/react-accordion": "^9.10.0", - "@fluentui/react-alert": "9.0.0-beta.138", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-avatar": "^9.11.0", - "@fluentui/react-badge": "^9.5.1", - "@fluentui/react-breadcrumb": "^9.4.0", - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-card": "^9.6.0", - "@fluentui/react-carousel": "^9.9.6", - "@fluentui/react-checkbox": "^9.6.0", - "@fluentui/react-color-picker": "^9.2.15", - "@fluentui/react-combobox": "^9.17.0", - "@fluentui/react-dialog": "^9.17.3", - "@fluentui/react-divider": "^9.7.0", - "@fluentui/react-drawer": "^9.11.6", - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-image": "^9.4.0", - "@fluentui/react-infobutton": "9.0.0-beta.114", - "@fluentui/react-infolabel": "^9.4.19", - "@fluentui/react-input": "^9.8.1", - "@fluentui/react-label": "^9.4.0", - "@fluentui/react-link": "^9.8.0", - "@fluentui/react-list": "^9.6.13", - "@fluentui/react-menu": "^9.24.0", - "@fluentui/react-message-bar": "^9.6.23", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-nav": "^9.3.23", - "@fluentui/react-overflow": "^9.7.1", - "@fluentui/react-persona": "^9.7.2", - "@fluentui/react-popover": "^9.14.1", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", - "@fluentui/react-progress": "^9.5.0", - "@fluentui/react-provider": "^9.22.15", - "@fluentui/react-radio": "^9.6.1", - "@fluentui/react-rating": "^9.4.0", - "@fluentui/react-search": "^9.4.1", - "@fluentui/react-select": "^9.5.0", + "version": "9.74.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-components/-/react-components-9.74.1.tgz", + "integrity": "sha1-bEdHxyxg5dqk+DT+Kc80qpYm37c=", + "license": "MIT", + "dependencies": { + "@fluentui/react-accordion": "^9.12.0", + "@fluentui/react-alert": "9.0.0-beta.140", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-avatar": "^9.11.2", + "@fluentui/react-badge": "^9.5.3", + "@fluentui/react-breadcrumb": "^9.4.2", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-card": "^9.7.0", + "@fluentui/react-carousel": "^9.9.8", + "@fluentui/react-checkbox": "^9.6.2", + "@fluentui/react-color-picker": "^9.2.17", + "@fluentui/react-combobox": "^9.17.2", + "@fluentui/react-dialog": "^9.18.1", + "@fluentui/react-divider": "^9.7.2", + "@fluentui/react-drawer": "^9.13.0", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-image": "^9.4.2", + "@fluentui/react-infobutton": "9.0.0-beta.116", + "@fluentui/react-infolabel": "^9.4.21", + "@fluentui/react-input": "^9.8.3", + "@fluentui/react-label": "^9.4.2", + "@fluentui/react-link": "^9.8.2", + "@fluentui/react-list": "^9.6.15", + "@fluentui/react-menu": "^9.25.0", + "@fluentui/react-message-bar": "^9.7.1", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-nav": "^9.4.0", + "@fluentui/react-overflow": "^9.8.0", + "@fluentui/react-persona": "^9.7.4", + "@fluentui/react-popover": "^9.14.3", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", + "@fluentui/react-progress": "^9.5.2", + "@fluentui/react-provider": "^9.22.17", + "@fluentui/react-radio": "^9.6.3", + "@fluentui/react-rating": "^9.4.2", + "@fluentui/react-search": "^9.4.3", + "@fluentui/react-select": "^9.5.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-skeleton": "^9.7.1", - "@fluentui/react-slider": "^9.6.1", - "@fluentui/react-spinbutton": "^9.6.1", - "@fluentui/react-spinner": "^9.8.1", - "@fluentui/react-swatch-picker": "^9.5.1", - "@fluentui/react-switch": "^9.7.1", - "@fluentui/react-table": "^9.19.14", - "@fluentui/react-tabs": "^9.12.0", - "@fluentui/react-tabster": "^9.26.13", - "@fluentui/react-tag-picker": "^9.8.5", - "@fluentui/react-tags": "^9.8.0", - "@fluentui/react-teaching-popover": "^9.6.20", - "@fluentui/react-text": "^9.6.15", - "@fluentui/react-textarea": "^9.7.1", + "@fluentui/react-skeleton": "^9.7.3", + "@fluentui/react-slider": "^9.6.3", + "@fluentui/react-spinbutton": "^9.6.3", + "@fluentui/react-spinner": "^9.8.3", + "@fluentui/react-swatch-picker": "^9.5.3", + "@fluentui/react-switch": "^9.7.3", + "@fluentui/react-table": "^9.19.16", + "@fluentui/react-tabs": "^9.12.2", + "@fluentui/react-tabster": "^9.26.15", + "@fluentui/react-tag-picker": "^9.8.8", + "@fluentui/react-tags": "^9.9.1", + "@fluentui/react-teaching-popover": "^9.7.0", + "@fluentui/react-text": "^9.6.17", + "@fluentui/react-textarea": "^9.7.3", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-toast": "^9.7.16", - "@fluentui/react-toolbar": "^9.7.7", - "@fluentui/react-tooltip": "^9.10.0", - "@fluentui/react-tree": "^9.15.16", - "@fluentui/react-utilities": "^9.26.2", - "@fluentui/react-virtualizer": "9.0.0-alpha.111", + "@fluentui/react-toast": "^9.8.0", + "@fluentui/react-toolbar": "^9.8.1", + "@fluentui/react-tooltip": "^9.10.2", + "@fluentui/react-tree": "^9.16.1", + "@fluentui/react-utilities": "^9.26.4", + "@fluentui/react-virtualizer": "9.0.0-alpha.113", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1469,12 +1035,12 @@ } }, "node_modules/@fluentui/react-context-selector": { - "version": "9.2.15", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-context-selector/-/react-context-selector-9.2.15.tgz", - "integrity": "sha1-K1wttRHWH6uK8Dxf1qrwNvxN6Y0=", + "version": "9.2.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-context-selector/-/react-context-selector-9.2.17.tgz", + "integrity": "sha1-EtSv/66uiAhu5mVK5R/w9SfaQPM=", "license": "MIT", "dependencies": { - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1486,23 +1052,23 @@ } }, "node_modules/@fluentui/react-dialog": { - "version": "9.17.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-dialog/-/react-dialog-9.17.3.tgz", - "integrity": "sha1-9XCF9T9vbqe40Wvl2MGicKBXocs=", + "version": "9.18.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-dialog/-/react-dialog-9.18.1.tgz", + "integrity": "sha1-cs46DqmcBwwUFk/gnJ24p7ZOJK0=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-portal": "^9.8.11", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-portal": "^9.8.13", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1514,15 +1080,15 @@ } }, "node_modules/@fluentui/react-divider": { - "version": "9.7.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-divider/-/react-divider-9.7.0.tgz", - "integrity": "sha1-uC6aulubboKTGOJ0lTBxjJkdMqI=", + "version": "9.7.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-divider/-/react-divider-9.7.2.tgz", + "integrity": "sha1-JE1BOZbu1JG3HXdeGPZE1N+pQk8=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1534,20 +1100,20 @@ } }, "node_modules/@fluentui/react-drawer": { - "version": "9.11.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-drawer/-/react-drawer-9.11.6.tgz", - "integrity": "sha1-omFOPuxdJx+5MOzmyp/mIZgY4FI=", + "version": "9.13.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-drawer/-/react-drawer-9.13.0.tgz", + "integrity": "sha1-zbCnkPbMycf0HcapgPQvOUatRrc=", "license": "MIT", "dependencies": { - "@fluentui/react-dialog": "^9.17.3", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-portal": "^9.8.11", + "@fluentui/react-dialog": "^9.18.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-portal": "^9.8.13", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1559,18 +1125,18 @@ } }, "node_modules/@fluentui/react-field": { - "version": "9.5.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-field/-/react-field-9.5.0.tgz", - "integrity": "sha1-iYslG8hvbxyL6QTmFJUgnzjLrTg=", + "version": "9.5.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-field/-/react-field-9.5.2.tgz", + "integrity": "sha1-qZ/D3GPzpHuUJeW2gkaKxzrsncw=", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1582,15 +1148,15 @@ } }, "node_modules/@fluentui/react-focus": { - "version": "8.10.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-focus/-/react-focus-8.10.5.tgz", - "integrity": "sha1-Cy/s2fm9nRd5d8DAgNmd/q5HaPM=", + "version": "8.10.6", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-focus/-/react-focus-8.10.6.tgz", + "integrity": "sha1-08PPznH7re4nipLMtHi6Gtf1lUs=", "license": "MIT", "dependencies": { "@fluentui/keyboard-key": "^0.4.23", "@fluentui/merge-styles": "^8.6.14", "@fluentui/set-version": "^8.2.24", - "@fluentui/style-utilities": "^8.15.0", + "@fluentui/style-utilities": "^8.15.1", "@fluentui/utilities": "^8.17.2", "tslib": "^2.1.0" }, @@ -1616,9 +1182,9 @@ } }, "node_modules/@fluentui/react-icons": { - "version": "2.0.323", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-icons/-/react-icons-2.0.323.tgz", - "integrity": "sha1-53VjE7u6qItxfycg9qc/PuXdT1g=", + "version": "2.0.330", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-icons/-/react-icons-2.0.330.tgz", + "integrity": "sha1-PZxlc2AvVFokNfMJfU1hvMqLI50=", "license": "MIT", "dependencies": { "@griffel/react": "^1.6.1", @@ -1629,15 +1195,15 @@ } }, "node_modules/@fluentui/react-image": { - "version": "9.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-image/-/react-image-9.4.0.tgz", - "integrity": "sha1-klN3uvGD3gOpFSL7cFHaAryobhg=", + "version": "9.4.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-image/-/react-image-9.4.2.tgz", + "integrity": "sha1-nhhkOLzVmuypF5UwrzUVNrjBfDg=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1649,18 +1215,18 @@ } }, "node_modules/@fluentui/react-infobutton": { - "version": "9.0.0-beta.114", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.114.tgz", - "integrity": "sha1-dFDz3J6zHauPb8HA6Q1zC8q16Pc=", + "version": "9.0.0-beta.116", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.116.tgz", + "integrity": "sha1-376XhUE+ghnoUk6iiwB/O1fHwxk=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.237", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", - "@fluentui/react-popover": "^9.14.1", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", + "@fluentui/react-popover": "^9.14.3", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1672,19 +1238,19 @@ } }, "node_modules/@fluentui/react-infolabel": { - "version": "9.4.19", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-infolabel/-/react-infolabel-9.4.19.tgz", - "integrity": "sha1-Rm2TnlrAJ1SQah1h1z+MwStjNI8=", + "version": "9.4.21", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-infolabel/-/react-infolabel-9.4.21.tgz", + "integrity": "sha1-xcD4XHo6h4TMaWHxysK9UsxRQpI=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", - "@fluentui/react-popover": "^9.14.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", + "@fluentui/react-popover": "^9.14.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1696,16 +1262,16 @@ } }, "node_modules/@fluentui/react-input": { - "version": "9.8.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-input/-/react-input-9.8.1.tgz", - "integrity": "sha1-SwWmzbvbJY00/OZ6vU28i7GWnPo=", + "version": "9.8.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-input/-/react-input-9.8.3.tgz", + "integrity": "sha1-yBmSrbLKpfMZFiizC1yqB3ldxU4=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1717,12 +1283,12 @@ } }, "node_modules/@fluentui/react-jsx-runtime": { - "version": "9.4.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.4.1.tgz", - "integrity": "sha1-/3+tWSNfJINeYqd0MJbSzUiaC9c=", + "version": "9.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.4.3.tgz", + "integrity": "sha1-fL7Cl2NRZP4xV1J+oBzuhJjT4lk=", "license": "MIT", "dependencies": { - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1731,15 +1297,15 @@ } }, "node_modules/@fluentui/react-label": { - "version": "9.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-label/-/react-label-9.4.0.tgz", - "integrity": "sha1-Zw6oTirzUHcpK42J8kEtCV5fGAk=", + "version": "9.4.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-label/-/react-label-9.4.2.tgz", + "integrity": "sha1-Yh1o3KytZC4HULJ3k+nfV9EuDEw=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1751,17 +1317,17 @@ } }, "node_modules/@fluentui/react-link": { - "version": "9.8.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-link/-/react-link-9.8.0.tgz", - "integrity": "sha1-zNVWZQsPFheaWQFhTpDl6fQQkiM=", + "version": "9.8.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-link/-/react-link-9.8.2.tgz", + "integrity": "sha1-BNdTNxFColbjjhPt4F9i8k/6a0c=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1773,19 +1339,19 @@ } }, "node_modules/@fluentui/react-list": { - "version": "9.6.13", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-list/-/react-list-9.6.13.tgz", - "integrity": "sha1-wuF7xVFHme/R5cthgZ5htrDjGUE=", + "version": "9.6.15", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-list/-/react-list-9.6.15.tgz", + "integrity": "sha1-34dPIjtvb8FKAr4sPvcCml/gnfY=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-checkbox": "^9.6.0", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-checkbox": "^9.6.2", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1797,24 +1363,24 @@ } }, "node_modules/@fluentui/react-menu": { - "version": "9.24.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-menu/-/react-menu-9.24.0.tgz", - "integrity": "sha1-u0urp2Ib+JPlH22VQiu3WjvdTlU=", + "version": "9.25.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-menu/-/react-menu-9.25.0.tgz", + "integrity": "sha1-m8GcEB5Sn+i65EC4Su0F8FRGwnc=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1826,20 +1392,20 @@ } }, "node_modules/@fluentui/react-message-bar": { - "version": "9.6.23", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-message-bar/-/react-message-bar-9.6.23.tgz", - "integrity": "sha1-2yQXPSyg23Gz3M+5DkjZh1vig1U=", + "version": "9.7.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-message-bar/-/react-message-bar-9.7.1.tgz", + "integrity": "sha1-XtknJoDrQ2piHlMcjjGET88G35k=", "license": "MIT", "dependencies": { - "@fluentui/react-button": "^9.9.0", + "@fluentui/react-button": "^9.9.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-link": "^9.8.0", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-link": "^9.8.2", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1851,13 +1417,13 @@ } }, "node_modules/@fluentui/react-motion": { - "version": "9.14.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-motion/-/react-motion-9.14.0.tgz", - "integrity": "sha1-ICW8FZmNUQwKumnUbTNzmyfoefA=", + "version": "9.16.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-motion/-/react-motion-9.16.0.tgz", + "integrity": "sha1-jr2tS6aR4It6mzvG3YejmdlXLyM=", "license": "MIT", "dependencies": { "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@swc/helpers": "^0.5.1" }, "peerDependencies": { @@ -1868,9 +1434,9 @@ } }, "node_modules/@fluentui/react-motion-components-preview": { - "version": "0.15.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.15.3.tgz", - "integrity": "sha1-weuCVCGu3/UGwpBKwVKcXTl+rTA=", + "version": "0.15.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.15.5.tgz", + "integrity": "sha1-w/E7CM2tIDVwuA7/SUXlot2O+10=", "license": "MIT", "dependencies": { "@fluentui/react-motion": "*", @@ -1885,25 +1451,25 @@ } }, "node_modules/@fluentui/react-nav": { - "version": "9.3.23", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-nav/-/react-nav-9.3.23.tgz", - "integrity": "sha1-WDbcgXP/XOtDoSRE3dGgHyUiHKY=", + "version": "9.4.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-nav/-/react-nav-9.4.0.tgz", + "integrity": "sha1-5KaVzbNR8FxgLT2fVsO7SZKe1bI=", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-divider": "^9.7.0", - "@fluentui/react-drawer": "^9.11.6", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-divider": "^9.7.2", + "@fluentui/react-drawer": "^9.13.0", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-tooltip": "^9.10.0", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-tooltip": "^9.10.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1915,15 +1481,16 @@ } }, "node_modules/@fluentui/react-overflow": { - "version": "9.7.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-overflow/-/react-overflow-9.7.1.tgz", - "integrity": "sha1-mJhYIaiG0YVNPhKtNHpimXQ1ChU=", + "version": "9.8.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-overflow/-/react-overflow-9.8.0.tgz", + "integrity": "sha1-CoRcRK2lyrEAKIXTf4bCTAWKh28=", "license": "MIT", "dependencies": { "@fluentui/priority-overflow": "^9.3.0", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1935,17 +1502,17 @@ } }, "node_modules/@fluentui/react-persona": { - "version": "9.7.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-persona/-/react-persona-9.7.2.tgz", - "integrity": "sha1-PUvm8/xDbfP6jUC7yoPLpykPLAk=", + "version": "9.7.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-persona/-/react-persona-9.7.4.tgz", + "integrity": "sha1-LL+k+oL5MQdxnlOw1+o319guVHQ=", "license": "MIT", "dependencies": { - "@fluentui/react-avatar": "^9.11.0", - "@fluentui/react-badge": "^9.5.1", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-avatar": "^9.11.2", + "@fluentui/react-badge": "^9.5.3", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1957,23 +1524,23 @@ } }, "node_modules/@fluentui/react-popover": { - "version": "9.14.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-popover/-/react-popover-9.14.1.tgz", - "integrity": "sha1-oHquBDz3VHDO1qOzcZ4o2xXu+yc=", + "version": "9.14.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-popover/-/react-popover-9.14.3.tgz", + "integrity": "sha1-vHMvGogd6tRbU/wnSM1doham19s=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -1985,14 +1552,14 @@ } }, "node_modules/@fluentui/react-portal": { - "version": "9.8.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-portal/-/react-portal-9.8.11.tgz", - "integrity": "sha1-tnzs4dAYoJTYvQ7ZGY6YVrpBZpo=", + "version": "9.8.13", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-portal/-/react-portal-9.8.13.tgz", + "integrity": "sha1-xbWPuvfFvtKFevx3+osmYWpDbqU=", "license": "MIT", "dependencies": { "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-tabster": "^9.26.15", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2017,16 +1584,16 @@ } }, "node_modules/@fluentui/react-positioning": { - "version": "9.22.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-positioning/-/react-positioning-9.22.0.tgz", - "integrity": "sha1-dQ6kSPWyJIBi/AP1Wn2QnN4udT4=", + "version": "9.22.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-positioning/-/react-positioning-9.22.2.tgz", + "integrity": "sha1-SRc5Pc0JnyiztESImhAvjougsAU=", "license": "MIT", "dependencies": { "@floating-ui/devtools": "^0.2.3", "@floating-ui/dom": "^1.6.12", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1", "use-sync-external-store": "^1.2.0" @@ -2039,17 +1606,17 @@ } }, "node_modules/@fluentui/react-progress": { - "version": "9.5.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-progress/-/react-progress-9.5.0.tgz", - "integrity": "sha1-2nZjCynu+scz0Ty1TvxPn5Xc6LU=", + "version": "9.5.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-progress/-/react-progress-9.5.2.tgz", + "integrity": "sha1-WcJF6sm8YVDgKNlK3NgE3rfFxUM=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2061,17 +1628,17 @@ } }, "node_modules/@fluentui/react-provider": { - "version": "9.22.15", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-provider/-/react-provider-9.22.15.tgz", - "integrity": "sha1-eco1V4cN3oo8yKE6iAB40pVCvBs=", + "version": "9.22.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-provider/-/react-provider-9.22.17.tgz", + "integrity": "sha1-gan0yrk6Hvp9WQFo05InjOknkUo=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/core": "^1.16.0", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" @@ -2084,18 +1651,18 @@ } }, "node_modules/@fluentui/react-radio": { - "version": "9.6.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-radio/-/react-radio-9.6.1.tgz", - "integrity": "sha1-Yv1wRGsfb4emHAusV5OS7tBxz9w=", + "version": "9.6.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-radio/-/react-radio-9.6.3.tgz", + "integrity": "sha1-WVb/AMCT0d5rNEJDm/1TSXYpCuc=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2107,17 +1674,17 @@ } }, "node_modules/@fluentui/react-rating": { - "version": "9.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-rating/-/react-rating-9.4.0.tgz", - "integrity": "sha1-ocTKuI0SYk0z16mH2wZ7UUkGCaI=", + "version": "9.4.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-rating/-/react-rating-9.4.2.tgz", + "integrity": "sha1-NLVBC6dlqyT8eezeK/ztNFbIGWc=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2129,17 +1696,17 @@ } }, "node_modules/@fluentui/react-search": { - "version": "9.4.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-search/-/react-search-9.4.1.tgz", - "integrity": "sha1-qQTZOFi8xIC2zPbl3YXtOILzDrY=", + "version": "9.4.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-search/-/react-search-9.4.3.tgz", + "integrity": "sha1-Q8hdvTRf+823S9mQLfzZ5EWlsUM=", "license": "MIT", "dependencies": { "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-input": "^9.8.1", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-input": "^9.8.3", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2151,17 +1718,17 @@ } }, "node_modules/@fluentui/react-select": { - "version": "9.5.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-select/-/react-select-9.5.0.tgz", - "integrity": "sha1-OlyQs+kQft61O/DpSULYVUyQ4fA=", + "version": "9.5.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-select/-/react-select-9.5.2.tgz", + "integrity": "sha1-uVvQUFGLg6vMaGQCW49hsvxDpMM=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2187,16 +1754,16 @@ } }, "node_modules/@fluentui/react-skeleton": { - "version": "9.7.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-skeleton/-/react-skeleton-9.7.1.tgz", - "integrity": "sha1-VdJRGQ1JT6d3tTJUQxSCP16VXks=", + "version": "9.7.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-skeleton/-/react-skeleton-9.7.3.tgz", + "integrity": "sha1-3Ifb2mDXkyqXZ5eJEiYqezKruA4=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2208,17 +1775,17 @@ } }, "node_modules/@fluentui/react-slider": { - "version": "9.6.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-slider/-/react-slider-9.6.1.tgz", - "integrity": "sha1-uZHerW1dtY+u2CLSnFRDagBydZ0=", + "version": "9.6.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-slider/-/react-slider-9.6.3.tgz", + "integrity": "sha1-BBY4WBTEan+uBq3Fb7fXWqMBqPs=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2230,18 +1797,18 @@ } }, "node_modules/@fluentui/react-spinbutton": { - "version": "9.6.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-spinbutton/-/react-spinbutton-9.6.1.tgz", - "integrity": "sha1-BCJcaHuewtJwCpVFdr5Kj8fHfdQ=", + "version": "9.6.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-spinbutton/-/react-spinbutton-9.6.3.tgz", + "integrity": "sha1-Oy0YQ7CA4rrAb1boTbHShoJeT+4=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2253,16 +1820,16 @@ } }, "node_modules/@fluentui/react-spinner": { - "version": "9.8.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-spinner/-/react-spinner-9.8.1.tgz", - "integrity": "sha1-tbUy9XPy0S7rG870BqDsWyLlC5w=", + "version": "9.8.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-spinner/-/react-spinner-9.8.3.tgz", + "integrity": "sha1-ipjPqZ6tiT51dX/dn/XgWua30Nk=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2274,19 +1841,19 @@ } }, "node_modules/@fluentui/react-swatch-picker": { - "version": "9.5.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-swatch-picker/-/react-swatch-picker-9.5.1.tgz", - "integrity": "sha1-N/EquhPJ7vLigu5pS8E7/bzkD4g=", + "version": "9.5.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-swatch-picker/-/react-swatch-picker-9.5.3.tgz", + "integrity": "sha1-jbZDu1QpFlmD7uByAcZRsJ41ddk=", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2298,19 +1865,19 @@ } }, "node_modules/@fluentui/react-switch": { - "version": "9.7.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-switch/-/react-switch-9.7.1.tgz", - "integrity": "sha1-DtM9T+6k8INsE3tM7DzKoTgZHGU=", + "version": "9.7.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-switch/-/react-switch-9.7.3.tgz", + "integrity": "sha1-/OoWq6HIUFYrFdEcllwhjsOoB3A=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-label": "^9.4.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-label": "^9.4.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2322,23 +1889,23 @@ } }, "node_modules/@fluentui/react-table": { - "version": "9.19.14", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-table/-/react-table-9.19.14.tgz", - "integrity": "sha1-OoblwBTQLM8eHONzlnOSkwg6lGs=", + "version": "9.19.16", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-table/-/react-table-9.19.16.tgz", + "integrity": "sha1-PutzillT/bv8ApAiGKwyZtce2JE=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-avatar": "^9.11.0", - "@fluentui/react-checkbox": "^9.6.0", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-avatar": "^9.11.2", + "@fluentui/react-checkbox": "^9.6.2", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-radio": "^9.6.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-radio": "^9.6.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2350,17 +1917,17 @@ } }, "node_modules/@fluentui/react-tabs": { - "version": "9.12.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tabs/-/react-tabs-9.12.0.tgz", - "integrity": "sha1-pBybKlu3o0WrScySOCDm/O1EdB8=", + "version": "9.12.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tabs/-/react-tabs-9.12.2.tgz", + "integrity": "sha1-kiSznaMJG5fPWBJf/x5maHITPtQ=", "license": "MIT", "dependencies": { - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2372,18 +1939,18 @@ } }, "node_modules/@fluentui/react-tabster": { - "version": "9.26.13", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tabster/-/react-tabster-9.26.13.tgz", - "integrity": "sha1-/Sqp/rhax3xPG16c52/kue6wpI8=", + "version": "9.26.15", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tabster/-/react-tabster-9.26.15.tgz", + "integrity": "sha1-QCOKxn+020iv4lw/ycKjUhtbCkY=", "license": "MIT", "dependencies": { "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1", - "keyborg": "^2.6.0", - "tabster": "^8.5.5" + "keyborg": "^2.14.1", + "tabster": "^8.8.0" }, "peerDependencies": { "@types/react": ">=16.14.0 <20.0.0", @@ -2393,25 +1960,25 @@ } }, "node_modules/@fluentui/react-tag-picker": { - "version": "9.8.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tag-picker/-/react-tag-picker-9.8.5.tgz", - "integrity": "sha1-fJSUcEfpU8uTa9LFRgFAucQzQZs=", + "version": "9.8.8", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tag-picker/-/react-tag-picker-9.8.8.tgz", + "integrity": "sha1-Wj3yeeBeOf+Rk9VsM3BRVpEeBzI=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-combobox": "^9.17.0", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-field": "^9.5.0", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-combobox": "^9.17.2", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-field": "^9.5.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", - "@fluentui/react-tags": "^9.8.0", + "@fluentui/react-tabster": "^9.26.15", + "@fluentui/react-tags": "^9.9.1", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2423,20 +1990,20 @@ } }, "node_modules/@fluentui/react-tags": { - "version": "9.8.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tags/-/react-tags-9.8.0.tgz", - "integrity": "sha1-jDdTmdfoehTuCUa7PB5s5aidQek=", + "version": "9.9.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tags/-/react-tags-9.9.1.tgz", + "integrity": "sha1-lfz9YvrAgGZdDeMz4Lh9eVXw3pI=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-avatar": "^9.11.0", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-avatar": "^9.11.2", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2448,21 +2015,21 @@ } }, "node_modules/@fluentui/react-teaching-popover": { - "version": "9.6.20", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-teaching-popover/-/react-teaching-popover-9.6.20.tgz", - "integrity": "sha1-6YtV/qDZ2xdD6mXKlDl/EkOic7A=", + "version": "9.7.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-teaching-popover/-/react-teaching-popover-9.7.0.tgz", + "integrity": "sha1-opJFMIhQcZ/hnwrpzlsROff05Hk=", "license": "MIT", "dependencies": { - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-popover": "^9.14.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-popover": "^9.14.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1", "use-sync-external-store": "^1.2.0" @@ -2475,15 +2042,15 @@ } }, "node_modules/@fluentui/react-text": { - "version": "9.6.15", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-text/-/react-text-9.6.15.tgz", - "integrity": "sha1-qPrEIAluWFGhaLg2JLX+FdW/ycM=", + "version": "9.6.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-text/-/react-text-9.6.17.tgz", + "integrity": "sha1-SrbvezVY5NxM+VgDGX8E8fj1yds=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2495,16 +2062,16 @@ } }, "node_modules/@fluentui/react-textarea": { - "version": "9.7.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-textarea/-/react-textarea-9.7.1.tgz", - "integrity": "sha1-M3BfI3sQ+XHAkMq0O8D9nyxRIz0=", + "version": "9.7.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-textarea/-/react-textarea-9.7.3.tgz", + "integrity": "sha1-ScbYSMrv1GTTDEmaDwA39h7dZAw=", "license": "MIT", "dependencies": { - "@fluentui/react-field": "^9.5.0", - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-field": "^9.5.2", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2526,22 +2093,22 @@ } }, "node_modules/@fluentui/react-toast": { - "version": "9.7.16", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-toast/-/react-toast-9.7.16.tgz", - "integrity": "sha1-9/MGybEtzlud1Udk/ZBKNx6mo1Q=", + "version": "9.8.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-toast/-/react-toast-9.8.0.tgz", + "integrity": "sha1-BHmpl6x0LojmnQJbMZKmf1qXTCI=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", + "@fluentui/react-aria": "^9.17.12", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-portal": "^9.8.11", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-portal": "^9.8.13", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2553,20 +2120,20 @@ } }, "node_modules/@fluentui/react-toolbar": { - "version": "9.7.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-toolbar/-/react-toolbar-9.7.7.tgz", - "integrity": "sha1-9O3JMt+dB9AulGT2Jr+DyyGBgrA=", + "version": "9.8.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-toolbar/-/react-toolbar-9.8.1.tgz", + "integrity": "sha1-w4eYwPdJWJ8Ujh12/f7+k1vF2dk=", "license": "MIT", "dependencies": { - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-context-selector": "^9.2.15", - "@fluentui/react-divider": "^9.7.0", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-radio": "^9.6.1", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-context-selector": "^9.2.17", + "@fluentui/react-divider": "^9.7.2", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-radio": "^9.6.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2578,19 +2145,19 @@ } }, "node_modules/@fluentui/react-tooltip": { - "version": "9.10.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tooltip/-/react-tooltip-9.10.0.tgz", - "integrity": "sha1-Ecbmr8F72n1a90vQbbN4wj98/Hg=", + "version": "9.10.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tooltip/-/react-tooltip-9.10.2.tgz", + "integrity": "sha1-XHjx86qUUQDDshL+z3rRY73OGII=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-portal": "^9.8.11", - "@fluentui/react-positioning": "^9.22.0", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-portal": "^9.8.13", + "@fluentui/react-positioning": "^9.22.2", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2602,26 +2169,26 @@ } }, "node_modules/@fluentui/react-tree": { - "version": "9.15.16", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tree/-/react-tree-9.15.16.tgz", - "integrity": "sha1-TwwzeBs3y50knZerRXDlYivDMC0=", + "version": "9.16.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-tree/-/react-tree-9.16.1.tgz", + "integrity": "sha1-nIXvr6FpghlvU3r4WCiTgQtO3Bg=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", - "@fluentui/react-aria": "^9.17.10", - "@fluentui/react-avatar": "^9.11.0", - "@fluentui/react-button": "^9.9.0", - "@fluentui/react-checkbox": "^9.6.0", - "@fluentui/react-context-selector": "^9.2.15", + "@fluentui/react-aria": "^9.17.12", + "@fluentui/react-avatar": "^9.11.2", + "@fluentui/react-button": "^9.9.2", + "@fluentui/react-checkbox": "^9.6.2", + "@fluentui/react-context-selector": "^9.2.17", "@fluentui/react-icons": "^2.0.245", - "@fluentui/react-jsx-runtime": "^9.4.1", - "@fluentui/react-motion": "^9.14.0", - "@fluentui/react-motion-components-preview": "^0.15.3", - "@fluentui/react-radio": "^9.6.1", + "@fluentui/react-jsx-runtime": "^9.4.3", + "@fluentui/react-motion": "^9.16.0", + "@fluentui/react-motion-components-preview": "^0.15.5", + "@fluentui/react-radio": "^9.6.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-tabster": "^9.26.13", + "@fluentui/react-tabster": "^9.26.15", "@fluentui/react-theme": "^9.2.1", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2633,9 +2200,9 @@ } }, "node_modules/@fluentui/react-utilities": { - "version": "9.26.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-utilities/-/react-utilities-9.26.2.tgz", - "integrity": "sha1-Z24f/EGCBopd3joWxcriX6WeI5Y=", + "version": "9.26.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-utilities/-/react-utilities-9.26.4.tgz", + "integrity": "sha1-Jt+PM0RxsKH2cNzUko3KDwo77HM=", "license": "MIT", "dependencies": { "@fluentui/keyboard-keys": "^9.0.8", @@ -2648,14 +2215,14 @@ } }, "node_modules/@fluentui/react-virtualizer": { - "version": "9.0.0-alpha.111", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.111.tgz", - "integrity": "sha1-+LwEYhk0O5iXLx1rGLGnRtCRdvM=", + "version": "9.0.0-alpha.113", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.113.tgz", + "integrity": "sha1-BNSjYkybSK3uj6ljd2daId/Jl9o=", "license": "MIT", "dependencies": { - "@fluentui/react-jsx-runtime": "^9.4.1", + "@fluentui/react-jsx-runtime": "^9.4.3", "@fluentui/react-shared-contexts": "^9.26.2", - "@fluentui/react-utilities": "^9.26.2", + "@fluentui/react-utilities": "^9.26.4", "@griffel/react": "^1.5.32", "@swc/helpers": "^0.5.1" }, @@ -2690,9 +2257,9 @@ } }, "node_modules/@fluentui/style-utilities": { - "version": "8.15.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/style-utilities/-/style-utilities-8.15.0.tgz", - "integrity": "sha1-Y/OAeJYXZyZmqEb5Xp/Mt67Nfho=", + "version": "8.15.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@fluentui/style-utilities/-/style-utilities-8.15.1.tgz", + "integrity": "sha1-t1u9pBIN7l+E//SM8KXqQIE+Xts=", "license": "MIT", "dependencies": { "@fluentui/merge-styles": "^8.6.14", @@ -2746,65 +2313,79 @@ } }, "node_modules/@griffel/core": { - "version": "1.20.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/core/-/core-1.20.1.tgz", - "integrity": "sha1-+svI0mDdOGBKYHht4sA1v4WcSwM=", + "version": "1.21.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/core/-/core-1.21.2.tgz", + "integrity": "sha1-kC4QAB4wMJhnOqpx1zCBAb3HiNc=", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.0", - "@griffel/style-types": "^1.4.0", - "csstype": "^3.1.3", + "@griffel/style-types": "^1.4.2", + "csstype": "^3.2.3", "rtl-css-js": "^1.16.1", - "stylis": "^4.2.0", + "stylis": "^4.4.0", "tslib": "^2.1.0" } }, "node_modules/@griffel/react": { - "version": "1.6.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/react/-/react-1.6.1.tgz", - "integrity": "sha1-PvnlS4/EMAkjZK2tsXJpFyl5fT0=", + "version": "1.7.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/react/-/react-1.7.4.tgz", + "integrity": "sha1-8Lp5CNojxQtMjDEFnOFZj/C5V84=", "license": "MIT", "dependencies": { - "@griffel/core": "^1.20.1", + "@griffel/core": "^1.21.2", "tslib": "^2.1.0" }, "peerDependencies": { - "react": ">=16.8.0 <20.0.0" + "react": ">=16.14.0 <20.0.0" } }, "node_modules/@griffel/style-types": { - "version": "1.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/style-types/-/style-types-1.4.0.tgz", - "integrity": "sha1-WOtVOFBuhgIYiosXup8LSNcDz0s=", + "version": "1.4.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@griffel/style-types/-/style-types-1.4.2.tgz", + "integrity": "sha1-T2aXpznqvCzteNK/9POMN+SOkRU=", "license": "MIT", "dependencies": { - "csstype": "^3.1.3" + "csstype": "^3.2.3" } }, "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha1-F8Vcp9Qmcz/jxWGQa4Fzwza0Cnc=", + "version": "0.19.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha1-qCcsoDsqz0kmcCIrIyC2xCG/3mA=", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@humanfs/types": "^0.15.0" + }, "engines": { "node": ">=18.18.0" } }, "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha1-giy3s6EsWiQKJPYhtaJBPiekXyY=", + "version": "0.16.8", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha1-j4AMzME/T4zTEW4tnAqUk52j4+0=", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanfs/core": "^0.19.1", + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", "@humanwhocodes/retry": "^0.4.0" }, "engines": { "node": ">=18.18.0" } }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha1-8qCfYgEjkLK/8/xvskjd7IwJoJA=", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -2849,6 +2430,7 @@ "integrity": "sha1-Y0Khn0Q0dRjJPkOxrGnes8Rlah8=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -2860,6 +2442,7 @@ "integrity": "sha1-N1xHbRlylHhRuh4Vro8SMEdEWqE=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -2871,6 +2454,7 @@ "integrity": "sha1-eg7mAfYPmaIMfHxf8MgDiMEYm9Y=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.0.0" } @@ -2880,7 +2464,8 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha1-aRKwDSxjHA0Vzhp6tXzWV/Ko+Lo=", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", @@ -2888,6 +2473,7 @@ "integrity": "sha1-2xXWeByTHzolGj2sOVAcmKYIL9A=", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2905,31 +2491,39 @@ "integrity": "sha1-08jXqxhvQicnuhEtbr5f6OQQUdk=", "license": "MIT" }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha1-R9K/TO9tRwsi9YMbQg+JZOC/dV8=", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.5", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz", + "integrity": "sha1-zM1uvEC5kd6mk2+RJrG4FVtsTJU=", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", - "integrity": "sha1-BD8UVxYjRSkFLvnhzh2Ef/vp5nQ=", - "cpu": [ - "arm" - ], + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha1-Ligu+eHSbga2jM0Utz8xCjss9/g=", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "funding": { + "url": "https://github.com/sponsors/Boshen" + } }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", - "integrity": "sha1-Aj4b0UbnUZCH39nosp5M+fjs01w=", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha1-VM6Pg4IhP0oxSgwve6g/gf/q5ZI=", "cpu": [ "arm64" ], @@ -2938,12 +2532,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", - "integrity": "sha1-Vcy1SHwCQZlUxXp6gGAohdYW4e4=", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha1-OI/KFWbBTADEtEb8OShjDn8Nlfw=", "cpu": [ "arm64" ], @@ -2952,12 +2549,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", - "integrity": "sha1-JUtlQEsUSIyDIl6IuIGTdq1xp4Q=", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha1-U/V94fWZ7PHbE4I8/IjBj7gJVK0=", "cpu": [ "x64" ], @@ -2966,26 +2566,15 @@ "optional": true, "os": [ "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", - "integrity": "sha1-Y3f/OMBSx2/K/7eyco0xcv5nb+Y=", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", - "integrity": "sha1-ujkCMJ0Ijq9xObkW8JtxQLKLQG0=", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha1-bz/dobeuqsnSaKUmgEtPuW5ONfE=", "cpu": [ "x64" ], @@ -2994,26 +2583,15 @@ "optional": true, "os": [ "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", - "integrity": "sha1-4BG5oUY4Jn5TtEYoboONva9T8Wc=", - "cpu": [ - "arm" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", - "integrity": "sha1-C86c6aAJSQq9KP2SLdl+1SExGv4=", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha1-2HpFS/WFzJZ2hJN36R1uN1KXMm8=", "cpu": [ "arm" ], @@ -3022,180 +2600,135 @@ "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", - "integrity": "sha1-b2z7vzJPu0zv8hOr338yL9RdJf8=", - "cpu": [ - "arm64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", - "integrity": "sha1-98s+7K6pwVHvdzQq8F84rpJL95U=", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha1-QZ/Wv2Es80jxBSjLzZTrq5YH2NE=", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", - "integrity": "sha1-SZv6xrtmn9iLtmQ1e/a+mWoouS8=", - "cpu": [ - "loong64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", - "integrity": "sha1-En36wIdkdkOWu+BEU8VF04o6tRg=", - "cpu": [ - "loong64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", - "integrity": "sha1-anL02VhSqsGDJsW/cIOT6POkG3A=", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha1-/MaRhpa7doRId+HkkwoY/Q03QGk=", "cpu": [ - "ppc64" + "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", - "integrity": "sha1-uoZ0ZmsA1vkGbLmldxqEMMNNLeY=", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha1-Mq7LfI2uXU8qjN5XoFjshpkVQvg=", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", - "integrity": "sha1-F8w4sqceMCVHytKbz3jQ2yYYySI=", - "cpu": [ - "riscv64" + "libc": [ + "glibc" ], - "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", - "integrity": "sha1-42pB4ti9JHMxvVz8E7jJUdM0VKI=", - "cpu": [ - "riscv64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", - "integrity": "sha1-FocmXx9L3qBybHYaWMLbmTNgnWg=", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha1-vtk0bqgea7i5PPEfXYi3fbiQt2M=", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", - "integrity": "sha1-Vqag2QdvKgWpdgMUk7JKIN3MDnc=", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha1-ZMLSb3Xf/ZtaH5dVegCudyUMjLc=", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", - "integrity": "sha1-vCQOu1uf2NQcqKgMtFhFLowYfg8=", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha1-WkUTLopHZZ7qrztUDClUqXyGD/M=", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", - "integrity": "sha1-b4DUigBsSy/6dyTpWj4z9pdYcq8=", - "cpu": [ - "x64" ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", - "integrity": "sha1-j2229w0KSKvYM7JjzW3T5xmcTA4=", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha1-KQUTBoxV6EnchFejKv7h17Csswk=", "cpu": [ "arm64" ], @@ -3204,40 +2737,51 @@ "optional": true, "os": [ "openharmony" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", - "integrity": "sha1-tomJv6gV0LPU4wLs2QvadEQ4sXc=", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha1-PZly2/GpU9PHr6pKDyDvKy458xs=", "cpu": [ - "arm64" + "wasm32" ], "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", - "integrity": "sha1-wJjkUzjFDyLxsohHY1TwJbdGKFs=", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha1-oASrYHoW1vA7y1VXKP+IivdXc60=", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", - "integrity": "sha1-LJ4VvhVbedBZmZU7FzeykDhC6QM=", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha1-4qJbNGkaHMihIJ195wkGMCbdDNs=", "cpu": [ "x64" ], @@ -3246,74 +2790,36 @@ "optional": true, "os": [ "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", - "integrity": "sha1-I7hgET6fh+6gFdH6OkJApStC/NQ=", - "cpu": [ - "x64" ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha1-4/zuCT+7XOdl4a0Ij/TeKIn2+b4=", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "license": "MIT" }, "node_modules/@swc/helpers": { - "version": "0.5.21", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@swc/helpers/-/helpers-0.5.21.tgz", - "integrity": "sha1-CxsCAxfuEoKGDKZvfpp8d5DwWuA=", + "version": "0.5.23", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha1-GSh9DYbZYrERN2A5pQx5KQLJqGo=", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" } }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha1-PfFfJ7qFMZyqB7oI0HIYibs5wBc=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha1-tYGSlMUReZV6+uw0FEL5NB5BCKk=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha1-VnJRNwHBshmbxtrWNqnXSRWGdm8=", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha1-B9cT1szg0mXJhJ2wy+YtP2Hzb3Q=", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha1-ErOhsz2x+crU3f8fYEq33QC/Rk4=", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@babel/types": "^7.28.2" + "tslib": "^2.4.0" } }, "node_modules/@types/debug": { @@ -3326,9 +2832,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha1-lYuRyZGxhnztMYvt6g4hXuBQcm4=", + "version": "1.0.9", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha1-zz8Oh2177hWpOrkluCv1cKOQSiQ=", "license": "MIT" }, "node_modules/@types/estree-jsx": { @@ -3372,9 +2878,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.19.17", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/node/-/node-22.19.17.tgz", - "integrity": "sha1-Cccfs0uiUQ+KyGU2Gx/LlVK4pYE=", + "version": "22.19.21", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/node/-/node-22.19.21.tgz", + "integrity": "sha1-XJ2EPqOFsx7pN6n3Q0Q4MGIKMt4=", "dev": true, "license": "MIT", "dependencies": { @@ -3388,9 +2894,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.28", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/react/-/react-18.3.28.tgz", - "integrity": "sha1-CoWxpyQ7QljZ9ib0N5e6GOtfh4E=", + "version": "18.3.31", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/react/-/react-18.3.31.tgz", + "integrity": "sha1-teleKP/M6rjZgvM/LrB24XZTwqQ=", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3413,17 +2919,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz", - "integrity": "sha1-y1MDi4PRZcoO+W1n2HXvvVbFD6g=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", + "integrity": "sha1-2yAnGXS5SjpU07lUTl9bNIFEhAA=", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.58.1", - "@typescript-eslint/type-utils": "8.58.1", - "@typescript-eslint/utils": "8.58.1", - "@typescript-eslint/visitor-keys": "8.58.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/type-utils": "8.61.0", + "@typescript-eslint/utils": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -3436,7 +2942,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.58.1", + "@typescript-eslint/parser": "^8.61.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -3452,16 +2958,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/parser/-/parser-8.58.1.tgz", - "integrity": "sha1-CUPspSKsQIvN1kmILD2VsQ/wD2I=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/parser/-/parser-8.61.0.tgz", + "integrity": "sha1-Gv5zyczOFreibWuV+UALDMw0r4c=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.58.1", - "@typescript-eslint/types": "8.58.1", - "@typescript-eslint/typescript-estree": "8.58.1", - "@typescript-eslint/visitor-keys": "8.58.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3" }, "engines": { @@ -3477,14 +2983,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/project-service/-/project-service-8.58.1.tgz", - "integrity": "sha1-x4eBscoewee8ZSLvuokxjG0kn+s=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/project-service/-/project-service-8.61.0.tgz", + "integrity": "sha1-QXov6sMujr0zbWPwaMO0K3Nuoaw=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.58.1", - "@typescript-eslint/types": "^8.58.1", + "@typescript-eslint/tsconfig-utils": "^8.61.0", + "@typescript-eslint/types": "^8.61.0", "debug": "^4.4.3" }, "engines": { @@ -3499,14 +3005,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/scope-manager/-/scope-manager-8.58.1.tgz", - "integrity": "sha1-NRaPVhurTj/RDdawPouDwVdHkhE=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz", + "integrity": "sha1-k8JSDQVlP+Zeue6Y78dP0BNKeFI=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.1", - "@typescript-eslint/visitor-keys": "8.58.1" + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3517,9 +3023,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.1.tgz", - "integrity": "sha1-6xZ5LFeTAMe/s8dLD14d+7CiRU0=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz", + "integrity": "sha1-Bdbj/yAAFnTrzSLQPawp7kSAQ7o=", "dev": true, "license": "MIT", "engines": { @@ -3534,15 +3040,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/type-utils/-/type-utils-8.58.1.tgz", - "integrity": "sha1-shCFojMIe96UySum9bTft3ylZzA=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz", + "integrity": "sha1-UCGbV+a4nOz7GhXwk7Feye4BmXQ=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.1", - "@typescript-eslint/typescript-estree": "8.58.1", - "@typescript-eslint/utils": "8.58.1", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -3559,9 +3065,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/types/-/types-8.58.1.tgz", - "integrity": "sha1-nftHI/zSsTc32LA9lBNUz3MZAxM=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/types/-/types-8.61.0.tgz", + "integrity": "sha1-DdtG4BKkKIKSlQvdJT20LyeM5k0=", "dev": true, "license": "MIT", "engines": { @@ -3573,16 +3079,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.1.tgz", - "integrity": "sha1-gjDMlijSz/7xAeKYxigHxLm/L+k=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz", + "integrity": "sha1-mMpHJgu/Yn/CjwGLOgq/AOMJBpA=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.58.1", - "@typescript-eslint/tsconfig-utils": "8.58.1", - "@typescript-eslint/types": "8.58.1", - "@typescript-eslint/visitor-keys": "8.58.1", + "@typescript-eslint/project-service": "8.61.0", + "@typescript-eslint/tsconfig-utils": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -3611,9 +3117,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha1-3MOjcRa3nz4bRtuZTO1dVw6TD9s=", + "version": "5.0.6", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha1-7Gj+CmQaKdhxFXnK9kHQW64fIoU=", "dev": true, "license": "MIT", "dependencies": { @@ -3640,9 +3146,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.7.4.tgz", - "integrity": "sha1-KEZONgYOmR+noR0CedLT87V6foo=", + "version": "7.8.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.8.4.tgz", + "integrity": "sha1-xz7O664GFpNL6N/yin/XB1fI5pY=", "dev": true, "license": "ISC", "bin": { @@ -3653,16 +3159,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/utils/-/utils-8.58.1.tgz", - "integrity": "sha1-CZoyewTtkh5u45iM3p7zS8S1Q1o=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/utils/-/utils-8.61.0.tgz", + "integrity": "sha1-7TVGoFJ4foTqbFBk0JGfxe6oUi8=", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.58.1", - "@typescript-eslint/types": "8.58.1", - "@typescript-eslint/typescript-estree": "8.58.1" + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3677,13 +3183,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.1.tgz", - "integrity": "sha1-fBl1Mxd/G6m4JJ9V9/aF4yu28gQ=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz", + "integrity": "sha1-ObThq4k20jvqlz05/QkvmqIfJ14=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/types": "8.61.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -3708,36 +3214,41 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha1-0Gu7OE689sUF/eHD0O1N3/4Kr/g=", + "version": "1.3.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha1-Do80hU33lmsJMEoY6AiyOZe7n8E=", "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha1-ZHr057t1rTrdV452KtmEuQ9KJLk=", + "version": "6.0.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@vitejs/plugin-react/-/plugin-react-6.0.2.tgz", + "integrity": "sha1-9wy47QziJdvDBV14Bw+CDYqjXto=", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" + "@rolldown/pluginutils": "^1.0.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } } }, "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha1-TOecib5Ar+ev6POtuQKh8c6awIo=", + "version": "8.17.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn/-/acorn-8.17.0.tgz", + "integrity": "sha1-F4WtuE+vjYrdEDabk4Jvwr0I8f4=", "dev": true, "license": "MIT", "bin": { @@ -3758,9 +3269,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha1-/QZ3E+IoIQY267CMYL03Zdbb5zo=", + "version": "6.15.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha1-B+mCx0YmFnqnoklcU4F4ktcTlJI=", "dev": true, "license": "MIT", "dependencies": { @@ -4058,11 +3569,12 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.16", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/baseline-browser-mapping/-/baseline-browser-mapping-2.10.16.tgz", - "integrity": "sha1-74DPIYpT8WVomm4y///cofNdl5w=", + "version": "2.10.37", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha1-PmNkdbaykyROKyPixxoqudnmun0=", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "baseline-browser-mapping": "dist/cli.cjs" }, @@ -4082,9 +3594,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha1-03h1wB3J7/mI3UnREqV8tntU7+Y=", + "version": "1.1.15", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha1-ptkNVAZyNuX0JXCjtzeNWU2bdzg=", "dev": true, "license": "MIT", "dependencies": { @@ -4125,6 +3637,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -4200,15 +3713,15 @@ "license": "MIT" }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha1-BzapZg9TfjOIgm9EDV7EX3ROqkw=", + "version": "1.0.9", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha1-OaZEcAyAvH0MqRAvxtHUOy/X7uc=", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -4260,9 +3773,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001787", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/caniuse-lite/-/caniuse-lite-1.0.30001787.tgz", - "integrity": "sha1-/SXF5C4tNd9cde3doA0V2cDGj4E=", + "version": "1.0.30001799", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha1-XJCROMJ/GmEhnT4JIHHBzH0y3FU=", "dev": true, "funding": [ { @@ -4278,7 +3791,8 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "CC-BY-4.0" + "license": "CC-BY-4.0", + "peer": true }, "node_modules/ccount": { "version": "2.0.1", @@ -4433,7 +3947,8 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha1-S1YPZJ/E6RjdCrdc9JYei8iC2Co=", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/core-util-is": { "version": "1.0.3", @@ -4659,6 +4174,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha1-aJxdzcGQDvVYOky59te0c3QgdK0=", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/devlop/-/devlop-1.1.0.tgz", @@ -4688,11 +4213,12 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.334", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/electron-to-chromium/-/electron-to-chromium-1.5.334.tgz", - "integrity": "sha1-Hj/djQFIUhBOuOYy52D7Nk233Q4=", + "version": "1.5.372", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/electron-to-chromium/-/electron-to-chromium-1.5.372.tgz", + "integrity": "sha1-rorGmUKjeyMXc7j7AXWfc3M1meM=", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/embla-carousel": { "version": "8.6.0", @@ -4825,9 +4351,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha1-HE8sSDcydZfOadLKGQp/3RcjOME=", + "version": "1.1.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha1-otCzcyBXJN+lJdI7DD4bHKWCyZs=", "dev": true, "license": "MIT", "dependencies": { @@ -4871,54 +4397,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha1-l6HQQfSrAML84vg40rmWmi0ql6U=", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/escalade/-/escalade-3.2.0.tgz", "integrity": "sha1-ARo/aYVroYnf+n3I/M6Z0qh5A+U=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6" } @@ -5337,18 +4822,21 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha1-5o4d97JZpclJ7u+Vzb3lPt/6u3g=", + "version": "1.2.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha1-dY8+hPpUJnJFS9XhTLCBpc4H9ww=", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5383,6 +4871,7 @@ "integrity": "sha1-MqbudsPX9S1GsrGuXZP+qFgKJeA=", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=6.9.0" } @@ -5518,9 +5007,9 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha1-3MOjcRa3nz4bRtuZTO1dVw6TD9s=", + "version": "5.0.6", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha1-7Gj+CmQaKdhxFXnK9kHQW64fIoU=", "dev": true, "license": "MIT", "dependencies": { @@ -5678,9 +5167,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha1-AD6vkb563DcuhOxZ3DclLO24AAM=", + "version": "2.0.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha1-jGLYy5C+sqrV0KW2dYGtmFTD8AM=", "dev": true, "license": "MIT", "dependencies": { @@ -5973,13 +5462,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha1-KpiAGoSfQ+Kt1kT7trxiKbGaTvQ=", + "version": "2.16.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha1-PgdFCoCA684/vwysSU9NKrMk4II=", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -6043,10 +5532,26 @@ "is-docker": "cli.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha1-FjpL+zYsbtexGM5GzezE433uMZU=", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-extglob": { @@ -6450,10 +5955,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha1-hUwpJGdwW2mUduGi3swMijRYgGs=", + "version": "4.2.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha1-K9noVoLdkb1GmvuAnYFgQ7PUlSQ=", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -6468,6 +5983,7 @@ "integrity": "sha1-dNM1ojT2ftGZB/2t+sfM+dQJgl0=", "dev": true, "license": "MIT", + "peer": true, "bin": { "jsesc": "bin/jsesc" }, @@ -6519,6 +6035,7 @@ "integrity": "sha1-eM1vGhm9wStz21rQxh79ZsHikoM=", "dev": true, "license": "MIT", + "peer": true, "bin": { "json5": "lib/cli.js" }, @@ -6540,9 +6057,9 @@ } }, "node_modules/keyborg": { - "version": "2.6.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/keyborg/-/keyborg-2.6.0.tgz", - "integrity": "sha1-6/yq7S9Rf5KVBY/11X0U5xlYq1o=", + "version": "2.14.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/keyborg/-/keyborg-2.14.1.tgz", + "integrity": "sha1-BElZ/w5PldBi0eB+LToPvCrRHTA=", "license": "MIT" }, "node_modules/keyv": { @@ -6592,6 +6109,279 @@ "immediate": "~3.0.5" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha1-uFqulkhtyxv0mnyFcSISc/Tx5Kk=", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha1-8DOIURbf79nG9UeHUj41FLYeGWg=", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha1-ULcYcbAcgZlYS2SeKSVH+up6+bU=", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha1-NfPpczLRMLnKGB4RtWje1q68bV4=", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha1-l3enZHK2Ttb/lDQq1kx7r9eUpXU=", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha1-E65lLhq3O5E117faFy9mbEEK1T0=", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha1-QXhYeVqUWS9oASOhsfnaig4e8zU=", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha1-a+NmkugQtxgECAL9gJYjz/5zITM=", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha1-C3gDr06yHP043Tn+Kru1PH3QkfY=", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha1-iNyLqGXd3bGsXvBLDxYYBEGMFjs=", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha1-TzC6P6XpJfW3n5RejMDRdsOxqzg=", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha1-FBqlYFZFBkkokCu0rwRfp9n0Igo=", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/locate-path/-/locate-path-6.0.0.tgz", @@ -6650,6 +6440,7 @@ "integrity": "sha1-HaJ+ZxAnGUdpXa9oSOhH8B2EuSA=", "dev": true, "license": "ISC", + "peer": true, "dependencies": { "yallist": "^3.0.2" } @@ -7386,9 +7177,9 @@ "license": "ISC" }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha1-T08RLO++MDIC8hmYOBKJNiZtGFs=", + "version": "3.3.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha1-qz2RLiF6bQpRTwCnKhZUOiiYLAU=", "dev": true, "funding": [ { @@ -7412,11 +7203,15 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha1-m9TxC3e6OcK5QC1Og5nEgqeX9nE=", + "version": "2.0.47", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha1-UhuyeG2o6xQLdIhBwLOzp1M0/8Q=", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } }, "node_modules/normalize-path": { "version": "2.1.1", @@ -7746,9 +7541,9 @@ } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.3.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lru-cache/-/lru-cache-11.3.3.tgz", - "integrity": "sha1-1sYzwqlld2D9MFlNjZjaZTMNnXg=", + "version": "11.5.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha1-89qjVAhHuXN+vAJJnds2dl5U20o=", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -7786,9 +7581,9 @@ } }, "node_modules/postcss": { - "version": "8.5.12", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/postcss/-/postcss-8.5.12.tgz", - "integrity": "sha1-zQwPZn98sFIeIxMjTqbnB6nsHds=", + "version": "8.5.15", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha1-0er2d6Mk6ewCGW2i0/7PSguac1w=", "dev": true, "funding": [ { @@ -7806,7 +7601,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7856,9 +7651,9 @@ "license": "MIT" }, "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha1-tiLoZG4CtYAgVBVYa0CATT6L/V0=", + "version": "7.2.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha1-CAmzQmTplcC/zTInAooeNSEK+Ao=", "license": "MIT", "funding": { "type": "github", @@ -7952,16 +7747,6 @@ "react": ">=18" } }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha1-t+V5w2V/I9BOzL5K0uWKjtUeflM=", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read": { "version": "1.0.7", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/read/-/read-1.0.7.tgz", @@ -8088,12 +7873,13 @@ "license": "ISC" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha1-qthXzh/7i/qbCxrCnxFWOD9owmI=", + "version": "1.22.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha1-9bKmgIl8acI4oTzRaxVnH4tzVJ8=", "dev": true, "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" @@ -8128,49 +7914,38 @@ "node": ">= 0.4.0" } }, - "node_modules/rollup": { - "version": "4.60.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup/-/rollup-4.60.1.tgz", - "integrity": "sha1-tKoryzpeFDe1+tQNQ/5C1L3npC0=", + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha1-24ijAI+w4oIwoAQjcnznW6MhIaw=", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { - "rollup": "dist/bin/rollup" + "rolldown": "bin/cli.mjs" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.1", - "@rollup/rollup-android-arm64": "4.60.1", - "@rollup/rollup-darwin-arm64": "4.60.1", - "@rollup/rollup-darwin-x64": "4.60.1", - "@rollup/rollup-freebsd-arm64": "4.60.1", - "@rollup/rollup-freebsd-x64": "4.60.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", - "@rollup/rollup-linux-arm-musleabihf": "4.60.1", - "@rollup/rollup-linux-arm64-gnu": "4.60.1", - "@rollup/rollup-linux-arm64-musl": "4.60.1", - "@rollup/rollup-linux-loong64-gnu": "4.60.1", - "@rollup/rollup-linux-loong64-musl": "4.60.1", - "@rollup/rollup-linux-ppc64-gnu": "4.60.1", - "@rollup/rollup-linux-ppc64-musl": "4.60.1", - "@rollup/rollup-linux-riscv64-gnu": "4.60.1", - "@rollup/rollup-linux-riscv64-musl": "4.60.1", - "@rollup/rollup-linux-s390x-gnu": "4.60.1", - "@rollup/rollup-linux-x64-gnu": "4.60.1", - "@rollup/rollup-linux-x64-musl": "4.60.1", - "@rollup/rollup-openbsd-x64": "4.60.1", - "@rollup/rollup-openharmony-arm64": "4.60.1", - "@rollup/rollup-win32-arm64-msvc": "4.60.1", - "@rollup/rollup-win32-ia32-msvc": "4.60.1", - "@rollup/rollup-win32-x64-gnu": "4.60.1", - "@rollup/rollup-win32-x64-msvc": "4.60.1", - "fsevents": "~2.3.2" + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, "node_modules/rtl-css-js": { @@ -8183,15 +7958,15 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha1-yeVOxPYDsLu45+UAel7nrs0VOMM=", + "version": "1.1.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha1-pUzJthpX8ztCq608vdo6KzjMVxk=", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -8281,6 +8056,7 @@ "integrity": "sha1-VW0u+GiRRuRtzqS/3QlfNDTf/LQ=", "dev": true, "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" } @@ -8404,15 +8180,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha1-w/z/nE2pMnhIczNeyXZfqU/2a8k=", + "version": "1.1.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha1-6gLGLgXcS+pn1EQvD7ce4ZL44Ks=", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -8547,19 +8323,20 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha1-QLLdXulMlZtNz7HWXOcukNpIDIE=", + "version": "1.2.11", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha1-5r0ZzaOYXQWkLdox89300100MOM=", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8569,16 +8346,16 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha1-YuJzEnLNKFBBs2WWBU6fZlabaUI=", + "version": "1.0.10", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha1-vmvPTz/gRgvezNss9PlxsxD4NG4=", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "es-object-atoms": "^1.1.2" }, "engines": { "node": ">= 0.4" @@ -8664,9 +8441,9 @@ } }, "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha1-fHuXGRy08ZXwPsq31S95Au03gyA=", + "version": "4.4.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha1-xYRsk0X0v8Ub0MvXyjWgdE9IWl0=", "license": "MIT" }, "node_modules/supports-color": { @@ -8709,31 +8486,15 @@ } }, "node_modules/tabster": { - "version": "8.7.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tabster/-/tabster-8.7.0.tgz", - "integrity": "sha1-8LTC9vJ+hK6mU4ldKiVdIVn4NJA=", + "version": "8.8.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tabster/-/tabster-8.8.0.tgz", + "integrity": "sha1-cE7yrsD91vQss1DXgfJIh32hmWw=", "license": "MIT", "dependencies": { - "keyborg": "2.6.0", + "keyborg": "^2.14.0", "tslib": "^2.8.1" - }, - "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "4.53.3" } }, - "node_modules/tabster/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha1-/Q3qO7mqB+cINXnyXhwihaRsufo=", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/tar-stream": { "version": "1.6.2", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tar-stream/-/tar-stream-1.6.2.tgz", @@ -8811,9 +8572,9 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.16", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tinyglobby/-/tinyglobby-0.2.16.tgz", - "integrity": "sha1-HDt+uVP85Csia8Wh7gZCgoGv89Y=", + "version": "0.2.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha1-ViqabJ6ys7Ej05cZ+a9btE/NdjE=", "dev": true, "license": "MIT", "dependencies": { @@ -8838,9 +8599,9 @@ } }, "node_modules/tmp": { - "version": "0.2.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tmp/-/tmp-0.2.6.tgz", - "integrity": "sha1-DfrBD9CakxkojrDo8O1SRgThg7Q=", + "version": "0.2.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha1-JvTbEdFgHOgBLcuKeY7OHAapkFk=", "dev": true, "license": "MIT", "engines": { @@ -9048,18 +8809,18 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha1-7k3v+YS2S+HhGLDejJyHfVznPT0=", + "version": "1.0.8", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha1-C3Dpgsnp2v4t721kWP9LPy0rbXA=", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" }, "engines": { "node": ">= 0.4" @@ -9100,16 +8861,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.58.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript-eslint/-/typescript-eslint-8.58.1.tgz", - "integrity": "sha1-52XL/qV3TctLFHPl53pGJU8wmzI=", + "version": "8.61.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript-eslint/-/typescript-eslint-8.61.0.tgz", + "integrity": "sha1-aSf7lPXyliPjcNM/2fph8V1tmWs=", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.58.1", - "@typescript-eslint/parser": "8.58.1", - "@typescript-eslint/typescript-estree": "8.58.1", - "@typescript-eslint/utils": "8.58.1" + "@typescript-eslint/eslint-plugin": "8.61.0", + "@typescript-eslint/parser": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9263,6 +9024,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -9376,24 +9138,23 @@ } }, "node_modules/vite": { - "version": "6.4.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/vite/-/vite-6.4.2.tgz", - "integrity": "sha1-pOVIyjqQyp83JFgsqzXhuhXvxvI=", + "version": "8.0.16", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/vite/-/vite-8.0.16.tgz", + "integrity": "sha1-rgc4ZsBlY9ZjSpAWmkluEb2E8aY=", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -9402,14 +9163,15 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -9418,13 +9180,16 @@ "@types/node": { "optional": true }, - "jiti": { + "@vitejs/devtools": { "optional": true }, - "less": { + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "lightningcss": { + "less": { "optional": true }, "sass": { @@ -9451,9 +9216,9 @@ } }, "node_modules/vite-plugin-singlefile": { - "version": "2.3.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.2.tgz", - "integrity": "sha1-4P+eFG+jpj/s1T6t6e0zvQjSDaA=", + "version": "2.3.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/vite-plugin-singlefile/-/vite-plugin-singlefile-2.3.3.tgz", + "integrity": "sha1-6FmupMDEt0/LumuvUn6I8q0J3mk=", "dev": true, "license": "MIT", "dependencies": { @@ -9464,7 +9229,12 @@ }, "peerDependencies": { "rollup": "^4.59.0", - "vite": "^5.4.11 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "vite": "^5.4.21 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/walkdir": { @@ -9568,14 +9338,14 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha1-P9t636/g6mkVexUJ86HNiSvR0SI=", + "version": "1.1.22", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha1-jzzHiu+0C0NzRt1Aodv6XR2kP+k=", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", @@ -9680,7 +9450,8 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yallist/-/yallist-3.1.1.tgz", "integrity": "sha1-27fa+b/YusmrRev2ArjLrQ1dCP0=", "dev": true, - "license": "ISC" + "license": "ISC", + "peer": true }, "node_modules/yocto-queue": { "version": "0.1.0", diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package.json b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package.json index ac672f1847f..a2488dd82b2 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package.json +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/package.json @@ -24,7 +24,7 @@ "@types/node": "^22.5.3", "@types/react": "^18.3.19", "@types/react-dom": "^18.3.0", - "@vitejs/plugin-react": "^4.3.1", + "@vitejs/plugin-react": "^6.0.2", "babel-plugin-transform-amd-to-commonjs": "^1.6.0", "eslint": "^9.9.0", "eslint-plugin-react-hooks": "^5.1.0-rc.0", @@ -34,7 +34,7 @@ "tfx-cli": "^0.21.0", "typescript": "^5.5.3", "typescript-eslint": "^8.27.0", - "vite": "^6.4.2", + "vite": "^8.0.16", "vite-plugin-singlefile": "^2.0.2" } } diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Safety/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Safety/README.md index 9bf406ba052..1e1f56b7981 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation.Safety/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation.Safety/README.md @@ -43,10 +43,13 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) ## Feedback & Contributing diff --git a/src/Libraries/Microsoft.Extensions.AI.Evaluation/README.md b/src/Libraries/Microsoft.Extensions.AI.Evaluation/README.md index dfc15311489..a2721d539fa 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Evaluation/README.md +++ b/src/Libraries/Microsoft.Extensions.AI.Evaluation/README.md @@ -43,11 +43,14 @@ You can optionally add the `Microsoft.Extensions.AI.Evaluation.Reporting.Azure` dotnet tool install Microsoft.Extensions.AI.Evaluation.Console --create-manifest-if-needed ``` -## Usage Examples +## Usage examples -For a comprehensive tour of all the functionality, concepts and APIs available in the `Microsoft.Extensions.AI.Evaluation` libraries, check out the [API Usage Examples](https://github.com/dotnet/ai-samples/blob/main/src/microsoft-extensions-ai-evaluation/api/) available in the [dotnet/ai-samples](https://github.com/dotnet/ai-samples) repo. These examples are structured as a collection of unit tests. Each unit test showcases a specific concept or API, and builds on the concepts and APIs showcased in previous unit tests. +For `Microsoft.Extensions.AI.Evaluation` library usage examples, see the following tutorials: +* [Quickstart: Evaluate response quality](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-ai-response) +* [Tutorial: Evaluate response quality with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-with-reporting) +* [Tutorial: Evaluate response safety with caching and reporting](https://learn.microsoft.com/dotnet/ai/evaluation/evaluate-safety) -## Feedback & Contributing +## Feedback & contributing We welcome feedback and contributions in [our GitHub repo](https://github.com/dotnet/extensions). diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIHostedFileClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIHostedFileClient.cs index 55ccfa1c10f..802aeacadc0 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIHostedFileClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIHostedFileClient.cs @@ -11,7 +11,6 @@ using System.Net.Http.Headers; using System.Net.Mime; using System.Runtime.CompilerServices; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Microsoft.Shared.DiagnosticIds; @@ -22,6 +21,7 @@ #pragma warning disable CA1031 // Do not catch general exception types #pragma warning disable IDE0058 // Expression value is never used +#pragma warning disable OPENAI001 // Container file APIs (ContainerFileResource) are experimental namespace Microsoft.Extensions.AI; @@ -126,8 +126,8 @@ public async Task UploadAsync( multipart.Headers.ContentType!.ToString(), requestOptions).ConfigureAwait(false); - using var responseDoc = JsonDocument.Parse(result.GetRawResponse().Content); - return ParseContainerFileJson(responseDoc.RootElement, containerId) + var uploadedFile = (ContainerFileResource)result; + return ToHostedFileContent(uploadedFile, containerId) ?? throw new InvalidOperationException("The container file upload response did not include a valid file ID."); } else @@ -161,13 +161,9 @@ public async Task DownloadAsync( var containerClient = GetContainerClient(); var containerResult = await containerClient.DownloadContainerFileAsync(containerId, fileId, cancellationToken).ConfigureAwait(false); - // Use protocol method to get file metadata as raw JSON. This works around - // https://github.com/openai/openai-dotnet/issues/733, where the SDK's typed - // deserialization crashes on container files with a null "bytes" value. var containerFileInfoResult = await containerClient.GetContainerFileAsync( - containerId, fileId, new RequestOptions { CancellationToken = cancellationToken }).ConfigureAwait(false); - using var infoDoc = JsonDocument.Parse(containerFileInfoResult.GetRawResponse().Content); - string? path = infoDoc.RootElement.TryGetProperty("path", out var pathProp) ? pathProp.GetString() : null; + containerId, fileId, cancellationToken).ConfigureAwait(false); + string? path = containerFileInfoResult.Value.Path; string containerFileName = path is not null ? Path.GetFileName(path) : fileId; string? containerMediaType = MediaTypeMap.GetMediaType(containerFileName) ?? "application/octet-stream"; @@ -197,14 +193,10 @@ public async Task DownloadAsync( { if (ResolveScope(options) is string containerId) { - // Use protocol method to get file metadata as raw JSON. This works around - // https://github.com/openai/openai-dotnet/issues/733, where the SDK's typed - // deserialization crashes on container files with a null "bytes" value. var containerResult = await GetContainerClient().GetContainerFileAsync( - containerId, fileId, new RequestOptions { CancellationToken = cancellationToken }).ConfigureAwait(false); + containerId, fileId, cancellationToken).ConfigureAwait(false); - using var doc = JsonDocument.Parse(containerResult.GetRawResponse().Content); - return ParseContainerFileJson(doc.RootElement, containerId); + return ToHostedFileContent(containerResult.Value, containerId); } else { @@ -227,73 +219,29 @@ public async IAsyncEnumerable ListFilesAsync( if (ResolveScope(options) is string containerId) { - // Use OpenAI's protocol overload to make single-page requests, handling paging manually. - // This works around https://github.com/openai/openai-dotnet/issues/733, where both - // the convenience and protocol collection overloads crash during auto-pagination when - // deserializing container files with a null "bytes" value. By only taking the first raw - // page from each request, the SDK's internal deserialization for pagination is never triggered. var containerClient = GetContainerClient(); int count = 0; - string? after = null; - - while (true) - { - AsyncCollectionResult result = containerClient.GetContainerFilesAsync( - containerId, limit < int.MaxValue ? limit : null, - null, after, new() { CancellationToken = cancellationToken }); - - // Get only the first raw page. We must not let the SDK auto-paginate - // because its pagination logic deserializes the full response, which crashes. - IAsyncEnumerator pages = result.GetRawPagesAsync().GetAsyncEnumerator(cancellationToken); - JsonDocument doc; - try + var files = containerClient.GetContainerFilesAsync( + new ContainerFileCollectionOptions(containerId) { - if (!await pages.MoveNextAsync().ConfigureAwait(false)) - { - break; - } + PageSizeLimit = limit < int.MaxValue ? limit : null, + }, cancellationToken); - doc = JsonDocument.Parse(pages.Current.GetRawResponse().Content); - } - finally + await foreach (var file in files.ConfigureAwait(false)) + { + if (count >= limit) { - await pages.DisposeAsync().ConfigureAwait(false); + yield break; } - using (doc) + if (ToHostedFileContent(file, containerId) is not { } hostedFile) { - var root = doc.RootElement; - - if (root.TryGetProperty("data", out JsonElement data) && data.ValueKind is JsonValueKind.Array) - { - foreach (var fileElement in data.EnumerateArray()) - { - if (count >= limit) - { - yield break; - } - - var file = ParseContainerFileJson(fileElement, containerId); - if (file is null) - { - continue; - } - - yield return file; - count++; - } - } - - bool hasMore = root.TryGetProperty("has_more", out var hm) && hm.ValueKind is JsonValueKind.True; - string? lastId = root.TryGetProperty("last_id", out var li) ? li.GetString() : null; - if (!hasMore || string.IsNullOrEmpty(lastId)) - { - break; - } - - after = lastId; + continue; } + + yield return hostedFile; + count++; } } else @@ -387,40 +335,23 @@ private static HostedFileContent ToHostedFileContent(OpenAIFile openAIFile) => RawRepresentation = openAIFile, }; - /// - /// Parses container file metadata from a JSON element into a . - /// - /// - /// This parses raw JSON rather than using the OpenAI SDK's typed deserialization, - /// as a workaround for , - /// where the SDK crashes deserializing container files when the "bytes" field is null. - /// Once the SDK issue is fixed, call sites should revert to using the typed API. - /// - private static HostedFileContent? ParseContainerFileJson(JsonElement element, string? scope) + private static HostedFileContent? ToHostedFileContent(ContainerFileResource file, string? scope) { - if (!element.TryGetProperty("id", out var idProp) || idProp.GetString() is not { } id) + if (string.IsNullOrEmpty(file.Id)) { return null; } - string? path = element.TryGetProperty("path", out var pathProp) ? pathProp.GetString() : null; - string name = path is not null ? Path.GetFileName(path) : id; - - long? sizeInBytes = element.TryGetProperty("bytes", out var bytesProp) && bytesProp.ValueKind is JsonValueKind.Number - ? bytesProp.GetInt64() - : null; - - DateTimeOffset? createdAt = element.TryGetProperty("created_at", out var createdProp) && createdProp.ValueKind is JsonValueKind.Number - ? DateTimeOffset.FromUnixTimeSeconds(createdProp.GetInt64()) - : null; + string name = file.Path is { } path ? Path.GetFileName(path) : file.Id; - return new HostedFileContent(id) + return new HostedFileContent(file.Id) { Name = name, MediaType = MediaTypeMap.GetMediaType(name), - SizeInBytes = sizeInBytes, - CreatedAt = createdAt, + SizeInBytes = file.SizeInBytes, + CreatedAt = file.CreatedAt, Scope = scope, + RawRepresentation = file, }; } diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAISpeechToTextClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAISpeechToTextClient.cs index b976f4a562a..c41db3a5e2e 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAISpeechToTextClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAISpeechToTextClient.cs @@ -24,10 +24,6 @@ namespace Microsoft.Extensions.AI; [Experimental(DiagnosticIds.Experiments.AISpeechToText, UrlFormat = DiagnosticIds.UrlFormat)] internal sealed class OpenAISpeechToTextClient : ISpeechToTextClient { - /// Filename to use when audio lacks a name. - /// This information internally is required but is only being used to create a header name in the multipart request. - private const string Filename = "audio.mp3"; - /// Metadata about the client. private readonly SpeechToTextClientMetadata _metadata; @@ -64,9 +60,7 @@ public async Task GetTextAsync( SpeechToTextResponse response = new(); - string filename = audioSpeechStream is FileStream fileStream ? - Path.GetFileName(fileStream.Name) : // Use the file name if we can get one from the stream. - Filename; // Otherwise, use a default name; this is only used to create a header name in the multipart request. + string filename = ResolveFilename(audioSpeechStream); if (IsTranslationRequest(options)) { @@ -120,9 +114,7 @@ public async IAsyncEnumerable GetStreamingTextAsync( { _ = Throw.IfNull(audioSpeechStream); - string filename = audioSpeechStream is FileStream fileStream ? - Path.GetFileName(fileStream.Name) : // Use the file name if we can get one from the stream. - Filename; // Otherwise, use a default name; this is only used to create a header name in the multipart request. + string filename = ResolveFilename(audioSpeechStream); if (IsTranslationRequest(options)) { @@ -185,6 +177,84 @@ options is not null && options.TextLanguage is not null && (options.SpeechLanguage is null || options.SpeechLanguage != options.TextLanguage); + /// + /// Resolves the filename to use for the audio stream in the multipart request. + /// Priority: name, then magic-byte detection (seekable streams only), then default. + /// + private static string ResolveFilename(Stream audioSpeechStream) + { + const int FormatDetectionByteCount = 12; + + if (audioSpeechStream is FileStream fileStream) + { + return Path.GetFileName(fileStream.Name); + } + + // For seekable streams positioned at the start, peek at the header to detect audio format, then rewind. + if (audioSpeechStream.CanSeek && audioSpeechStream.Position == 0) + { + byte[] header = new byte[FormatDetectionByteCount]; + int bytesRead = 0; + while (bytesRead < header.Length) + { + int n = audioSpeechStream.Read(header, bytesRead, header.Length - bytesRead); + if (n <= 0) + { + break; + } + + bytesRead += n; + } + + audioSpeechStream.Position -= bytesRead; + return $"audio.{DetectAudioExtension(header.AsSpan(0, bytesRead))}"; + } + + return "audio.mp3"; + } + + /// Detects the audio format extension from the leading bytes of the audio data. + private static string DetectAudioExtension(ReadOnlySpan header) + { + // WAV: "RIFF" at offset 0 and "WAVE" at offset 8. + if (header.Length >= 12 && + header.Slice(0, 4).SequenceEqual("RIFF"u8) && + header.Slice(8, 4).SequenceEqual("WAVE"u8)) + { + return "wav"; + } + + // WebM/Matroska: EBML header ID at offset 0. + if (header.Length >= 4 && + header.Slice(0, 4).SequenceEqual((ReadOnlySpan)[0x1A, 0x45, 0xDF, 0xA3])) + { + return "webm"; + } + + // M4A/MP4: ISO BMFF "ftyp" box type at offset 4. + if (header.Length >= 8 && + header.Slice(4, 4).SequenceEqual("ftyp"u8)) + { + return "m4a"; + } + + // MP3: ID3v2 tag at offset 0. + if (header.Length >= 3 && + header.Slice(0, 3).SequenceEqual("ID3"u8)) + { + return "mp3"; + } + + // MP3: MPEG frame sync word (11 set bits). + if (header.Length >= 2 && + header[0] == 0xFF && (header[1] & 0xE0) == 0xE0) + { + return "mp3"; + } + + return "mp3"; + } + /// Converts an extensions options instance to an OpenAI transcription options instance. private AudioTranscriptionOptions ToOpenAITranscriptionOptions(SpeechToTextOptions? options) { diff --git a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs index e0ff736a68d..da702dcf32a 100644 --- a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs @@ -355,7 +355,13 @@ public override async Task GetResponseAsync( anyToolsRequireApproval = AnyToolsRequireApproval(options?.Tools, AdditionalTools); if (anyToolsRequireApproval) { - response.Messages = ReplaceFunctionCallsWithApprovalRequests(response.Messages, options?.Tools, AdditionalTools); + var approvalRequiredFunctions = + (options?.Tools ?? Enumerable.Empty()) + .Concat(AdditionalTools ?? Enumerable.Empty()) + .Where(t => t.GetService() is not null) + .ToArray(); + + response.Messages = ReplaceFunctionCallsWithApprovalRequests(response.Messages, approvalRequiredFunctions); } // Any function call work to do? If yes, ensure we're tracking that work in functionCallContents. @@ -613,7 +619,7 @@ public override async IAsyncEnumerable GetStreamingResponseA for (; lastYieldedUpdateIndex < updates.Count; lastYieldedUpdateIndex++) { var updateToYield = updates[lastYieldedUpdateIndex]; - if (TryReplaceFunctionCallsWithApprovalRequests(updateToYield.Contents, out var updatedContents)) + if (TryReplaceFunctionCallsWithApprovalRequests(updateToYield.Contents, approvalRequiredFunctions, out var updatedContents)) { updateToYield.Contents = updatedContents; } @@ -1618,7 +1624,10 @@ private static (bool hasApprovalRequiringFcc, int lastApprovalCheckedFCCIndex) C /// Replaces all with and ouputs a new list if any of them were replaced. /// /// true if any was replaced, false otherwise. - private static bool TryReplaceFunctionCallsWithApprovalRequests(IList content, out List? updatedContent) + private static bool TryReplaceFunctionCallsWithApprovalRequests( + IList content, + AITool[] approvalRequiredFunctions, + out List? updatedContent) { updatedContent = null; @@ -1629,7 +1638,21 @@ private static bool TryReplaceFunctionCallsWithApprovalRequests(IList if (content[i] is FunctionCallContent fcc && !fcc.InformationalOnly) { updatedContent ??= [.. content]; // Clone the list if we haven't already - updatedContent[i] = new ToolApprovalRequestContent(ComposeApprovalRequestId(fcc.CallId), fcc); + + bool requiresConfirmation = false; + for (int j = 0; j < approvalRequiredFunctions.Length; j++) + { + if (string.Equals(approvalRequiredFunctions[j].Name, fcc.Name, StringComparison.Ordinal)) + { + requiresConfirmation = true; + break; + } + } + + updatedContent[i] = new ToolApprovalRequestContent(ComposeApprovalRequestId(fcc.CallId), fcc) + { + RequiresConfirmation = requiresConfirmation, + }; } } } @@ -1643,15 +1666,15 @@ private static bool TryReplaceFunctionCallsWithApprovalRequests(IList /// private IList ReplaceFunctionCallsWithApprovalRequests( IList messages, - params ReadOnlySpan?> toolLists) + AITool[] approvalRequiredFunctions) { var outputMessages = messages; bool anyApprovalRequired = false; - List<(int, int)>? allFunctionCallContentIndices = null; + List<(int MessageIndex, int ContentIndex, bool RequiresConfirmation)>? allFunctionCallContentIndices = null; // Build a list of the indices of all FunctionCallContent items. - // Also check if any of them require approval. + // Also check whether each call's target name matches an approval-required function. for (int i = 0; i < messages.Count; i++) { var content = messages[i].Contents; @@ -1659,9 +1682,19 @@ private IList ReplaceFunctionCallsWithApprovalRequests( { if (content[j] is FunctionCallContent functionCall && !functionCall.InformationalOnly) { - (allFunctionCallContentIndices ??= []).Add((i, j)); + bool requiresConfirmation = false; + for (int k = 0; k < approvalRequiredFunctions.Length; k++) + { + if (string.Equals(approvalRequiredFunctions[k].Name, functionCall.Name, StringComparison.Ordinal)) + { + requiresConfirmation = true; + break; + } + } + + (allFunctionCallContentIndices ??= []).Add((i, j, requiresConfirmation)); - anyApprovalRequired |= FindTool(functionCall.Name, toolLists)?.GetService() is not null; + anyApprovalRequired |= requiresConfirmation; } } } @@ -1676,7 +1709,7 @@ private IList ReplaceFunctionCallsWithApprovalRequests( outputMessages = [.. messages]; int lastMessageIndex = -1; - foreach (var (messageIndex, contentIndex) in allFunctionCallContentIndices!) + foreach (var (messageIndex, contentIndex, requiresConfirmation) in allFunctionCallContentIndices!) { // Clone the message if we didn't already clone it in a previous iteration. var message = lastMessageIndex != messageIndex ? outputMessages[messageIndex].Clone() : outputMessages[messageIndex]; @@ -1684,7 +1717,10 @@ private IList ReplaceFunctionCallsWithApprovalRequests( var functionCall = (FunctionCallContent)message.Contents[contentIndex]; LogFunctionRequiresApproval(functionCall.Name); - message.Contents[contentIndex] = new ToolApprovalRequestContent(ComposeApprovalRequestId(functionCall.CallId), functionCall); + message.Contents[contentIndex] = new ToolApprovalRequestContent(ComposeApprovalRequestId(functionCall.CallId), functionCall) + { + RequiresConfirmation = requiresConfirmation, + }; outputMessages[messageIndex] = message; lastMessageIndex = messageIndex; diff --git a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/ImageGeneratingChatClient.cs b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/ImageGeneratingChatClient.cs index f57fc966c01..bd11f7ad464 100644 --- a/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/ImageGeneratingChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI/ChatCompletion/ImageGeneratingChatClient.cs @@ -319,8 +319,8 @@ public IList ReplaceImageGenerationFunctionResults(IList c { List? newContents = null; - // Replace FunctionResultContent instances with generated image content - for (int i = contents.Count - 1; i >= 0; i--) + // Replace image-generation FunctionCallContent with ImageGenerationToolCallContent, and FunctionResultContent with generated image content + for (int i = 0; i < contents.Count; i++) { var content = contents[i]; @@ -328,7 +328,7 @@ public IList ReplaceImageGenerationFunctionResults(IList c if (content is FunctionCallContent functionCall && _toolNames.Contains(functionCall.Name)) { - // create a new list and omit the FunctionCallContent + // create a new list copying all items before this one, and omit the FunctionCallContent newContents ??= CopyList(contents, i); if (functionCall.Name != nameof(GetImagesForEdit)) @@ -339,6 +339,7 @@ public IList ReplaceImageGenerationFunctionResults(IList c else if (content is FunctionResultContent functionResult && _imageContentByCallId.TryGetValue(functionResult.CallId, out var imageContents)) { + // create a new list copying all items before this one newContents ??= CopyList(contents, i); if (imageContents.Any()) diff --git a/src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs b/src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs index 804d0d9f684..302cfd89314 100644 --- a/src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs +++ b/src/Libraries/Microsoft.Extensions.AI/OpenTelemetryConsts.cs @@ -47,9 +47,11 @@ public static class GenAI /// /// Operation name for realtime sessions. - /// This is a custom extension not part of the OpenTelemetry GenAI semantic conventions. - /// The spec allows using custom values for gen_ai.operation.name when standard values don't apply. /// + /// + /// This is a custom extension that is not part of the OpenTelemetry GenAI semantic conventions. + /// The spec allows using custom values for gen_ai.operation.name when standard values do not apply. + /// public const string RealtimeName = "realtime"; public const string SystemInstructions = "gen_ai.system_instructions"; @@ -184,26 +186,34 @@ public static class Realtime { /// /// The voice used for audio output in a realtime session. - /// Custom attribute: "gen_ai.realtime.voice". /// + /// + /// Custom attribute: gen_ai.realtime.voice. + /// public const string Voice = "gen_ai.realtime.voice"; /// - /// The output modalities configured for a realtime session (e.g., "Text", "Audio"). - /// Custom attribute: "gen_ai.realtime.output_modalities". + /// The output modalities configured for a realtime session (for example, "Text" and "Audio"). /// + /// + /// Custom attribute: gen_ai.realtime.output_modalities. + /// public const string OutputModalities = "gen_ai.realtime.output_modalities"; /// - /// The kind/type of realtime session (e.g., "TextInTextOut", "AudioInAudioOut"). - /// Custom attribute: "gen_ai.realtime.session_kind". + /// The kind or type of realtime session (for example, "TextInTextOut" and "AudioInAudioOut"). /// + /// + /// Custom attribute: gen_ai.realtime.session_kind. + /// public const string SessionKind = "gen_ai.realtime.session_kind"; /// - /// The modalities actually received in a realtime response (e.g., "text", "audio", "transcription"). - /// Custom attribute: "gen_ai.realtime.received_modalities". + /// The modalities actually received in a realtime response (for example, "text", "audio", and "transcription"). /// + /// + /// Custom attribute: gen_ai.realtime.received_modalities. + /// public const string ReceivedModalities = "gen_ai.realtime.received_modalities"; } } diff --git a/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/IngestionChunkerOptions.cs b/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/IngestionChunkerOptions.cs index 294f4c92d27..7010bb9cc29 100644 --- a/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/IngestionChunkerOptions.cs +++ b/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/IngestionChunkerOptions.cs @@ -32,8 +32,11 @@ public IngestionChunkerOptions(Tokenizer tokenizer) public Tokenizer Tokenizer { get; } /// - /// Gets or sets the maximum number of tokens allowed in each chunk. Default is 2000. + /// Gets or sets the maximum number of tokens allowed in each chunk. /// + /// + /// The default is 2000. + /// public int MaxTokensPerChunk { get => field == default ? DefaultTokensPerChunk : field; @@ -51,8 +54,11 @@ public int MaxTokensPerChunk } /// - /// Gets or sets the number of overlapping tokens between consecutive chunks. Default is 500. + /// Gets or sets the number of overlapping tokens between consecutive chunks. /// + /// + /// The default is 500. + /// public int OverlapTokens { get diff --git a/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/ValueStringBuilder.cs b/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/ValueStringBuilder.cs index 199d55262b3..2fd6c655c35 100644 --- a/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/ValueStringBuilder.cs +++ b/src/Libraries/Microsoft.Extensions.DataIngestion/Chunkers/ValueStringBuilder.cs @@ -69,7 +69,7 @@ public void NullTerminate() } /// - /// Get a pinnable reference to the builder. + /// Gets a pinnable reference to the builder. /// Does not ensure there is a null char after /// This overload is pattern matched in the C# 7.3+ compiler so you can omit /// the explicit method call, and write eg "fixed (char* c = builder)" diff --git a/src/Libraries/Microsoft.Extensions.DataIngestion/Processors/EnricherOptions.cs b/src/Libraries/Microsoft.Extensions.DataIngestion/Processors/EnricherOptions.cs index 182e07d9c1f..204a4794d20 100644 --- a/src/Libraries/Microsoft.Extensions.DataIngestion/Processors/EnricherOptions.cs +++ b/src/Libraries/Microsoft.Extensions.DataIngestion/Processors/EnricherOptions.cs @@ -41,8 +41,11 @@ public EnricherOptions(IChatClient chatClient) public ILoggerFactory? LoggerFactory { get; set; } /// - /// Gets or sets the batch size for processing chunks. Default is 20. + /// Gets or sets the batch size for processing chunks. /// + /// + /// The default is 20. + /// public int BatchSize { get; set => field = Throw.IfLessThanOrEqual(value, 0); } = 20; internal EnricherOptions Clone() => new(ChatClient) diff --git a/src/Libraries/Microsoft.Extensions.DataIngestion/Writers/VectorStoreWriterOptions.cs b/src/Libraries/Microsoft.Extensions.DataIngestion/Writers/VectorStoreWriterOptions.cs index cbc2036061a..3995ecb2815 100644 --- a/src/Libraries/Microsoft.Extensions.DataIngestion/Writers/VectorStoreWriterOptions.cs +++ b/src/Libraries/Microsoft.Extensions.DataIngestion/Writers/VectorStoreWriterOptions.cs @@ -11,8 +11,11 @@ namespace Microsoft.Extensions.DataIngestion; public sealed class VectorStoreWriterOptions { /// - /// Gets or sets the name of the collection. When not provided, "chunks" will be used. + /// Gets or sets the name of the collection. /// + /// + /// When not provided, "chunks" is used. + /// public string CollectionName { get => field ?? "chunks"; diff --git a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Metrics/MetricCollector.cs b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Metrics/MetricCollector.cs index 7102de8987c..30ff8461963 100644 --- a/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Metrics/MetricCollector.cs +++ b/src/Libraries/Microsoft.Extensions.Diagnostics.Testing/Metrics/MetricCollector.cs @@ -259,7 +259,7 @@ public async Task WaitForMeasurementsAsync(int minCount, TimeSpan timeout) } /// - /// Scan all registered observable instruments. + /// Records all registered observable instruments. /// public void RecordObservableInstruments() { diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Abstractions/IServiceEndpointBuilder.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Abstractions/IServiceEndpointBuilder.cs index e051b2bf746..0165aba3851 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Abstractions/IServiceEndpointBuilder.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Abstractions/IServiceEndpointBuilder.cs @@ -7,7 +7,7 @@ namespace Microsoft.Extensions.ServiceDiscovery; /// -/// Builder to create a instances. +/// Represents a builder that creates instances. /// public interface IServiceEndpointBuilder { diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsServiceEndpointProviderOptions.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsServiceEndpointProviderOptions.cs index b163afc76ff..4786dc97988 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsServiceEndpointProviderOptions.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsServiceEndpointProviderOptions.cs @@ -29,7 +29,10 @@ public class DnsServiceEndpointProviderOptions public double RetryBackOffFactor { get; set; } = 2; /// - /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. Defaults to false. + /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. /// + /// + /// The default delegate returns . + /// public Func ShouldApplyHostNameMetadata { get; set; } = _ => false; } diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsSrvServiceEndpointProviderOptions.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsSrvServiceEndpointProviderOptions.cs index c1d64136cc9..3cfee893d77 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsSrvServiceEndpointProviderOptions.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns/DnsSrvServiceEndpointProviderOptions.cs @@ -42,7 +42,10 @@ public class DnsSrvServiceEndpointProviderOptions public Func? ServiceDomainNameCallback { get; set; } /// - /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. Defaults to false. + /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. /// + /// + /// The default delegate returns . + /// public Func ShouldApplyHostNameMetadata { get; set; } = _ => false; } diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ConfigurationServiceEndpointProviderOptions.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ConfigurationServiceEndpointProviderOptions.cs index 29f28e359f7..65176cf5c49 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ConfigurationServiceEndpointProviderOptions.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ConfigurationServiceEndpointProviderOptions.cs @@ -11,12 +11,18 @@ namespace Microsoft.Extensions.ServiceDiscovery; public sealed class ConfigurationServiceEndpointProviderOptions { /// - /// The name of the configuration section which contains service endpoints. Defaults to "Services". + /// Gets or sets the name of the configuration section that contains service endpoints. /// + /// + /// The default value is "Services". + /// public string SectionName { get; set; } = "Services"; /// - /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. Defaults to a delegate which returns false. + /// Gets or sets a delegate used to determine whether to apply host name metadata to each resolved endpoint. /// + /// + /// The default delegate returns . + /// public Func ShouldApplyHostNameMetadata { get; set; } = _ => false; } diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Http/IServiceDiscoveryHttpMessageHandlerFactory.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Http/IServiceDiscoveryHttpMessageHandlerFactory.cs index 0c5bd02d10d..f3fba8cafc6 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Http/IServiceDiscoveryHttpMessageHandlerFactory.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Http/IServiceDiscoveryHttpMessageHandlerFactory.cs @@ -4,13 +4,13 @@ namespace Microsoft.Extensions.ServiceDiscovery.Http; /// -/// Factory which creates instances which resolve endpoints using service discovery +/// Represents a factory that creates instances that resolve endpoints using service discovery /// before delegating to a provided handler. /// public interface IServiceDiscoveryHttpMessageHandlerFactory { /// - /// Creates an instance which resolve endpoints using service discovery before + /// Creates an instance that resolves endpoints using service discovery before /// delegating to a provided handler. /// /// The handler to delegate to. diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Internal/ServiceEndpointResolverResult.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Internal/ServiceEndpointResolverResult.cs index 675941bb955..65161cac046 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Internal/ServiceEndpointResolverResult.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/Internal/ServiceEndpointResolverResult.cs @@ -18,7 +18,7 @@ internal sealed class ServiceEndpointResolverResult(ServiceEndpointSource? endpo public Exception? Exception { get; } = exception; /// - /// Gets a value indicating whether resolution completed successfully. + /// Gets a value that indicates whether resolution completed successfully. /// [MemberNotNullWhen(true, nameof(EndpointSource))] public bool ResolvedSuccessfully => Exception is null; diff --git a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ServiceDiscoveryOptions.cs b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ServiceDiscoveryOptions.cs index a6fd7123aa7..793f058a2cd 100644 --- a/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ServiceDiscoveryOptions.cs +++ b/src/Libraries/Microsoft.Extensions.ServiceDiscovery/ServiceDiscoveryOptions.cs @@ -12,10 +12,11 @@ namespace Microsoft.Extensions.ServiceDiscovery; public sealed class ServiceDiscoveryOptions { /// - /// Gets or sets a value indicating whether all URI schemes for URIs resolved by the service discovery system are allowed. - /// If this value is , all URI schemes are allowed. - /// If this value is , only the schemes specified in are allowed. + /// Gets or sets a value that indicates whether all URI schemes for URIs resolved by the service discovery system are allowed. /// + /// + /// to allow all URI schemes; to allow only schemes specified in . + /// public bool AllowAllSchemes { get; set; } = true; /// diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModel.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModel.cs index 10bc3d59f76..19093c30c7c 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModel.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModel.cs @@ -84,8 +84,10 @@ internal CollectionModel( /// /// Gets the single vector property in the model, and throws if there are multiple vector properties. - /// Suitable for providers where validation is in place for single vectors only (). /// + /// + /// This is suitable for providers where validation is in place for single vectors only (). + /// public VectorPropertyModel VectorProperty => _singleVectorProperty ??= VectorProperties.Single(); // TODO: the pattern of first instantiating via parameterless constructor and then populating the properties isn't compatible diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModelBuildingOptions.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModelBuildingOptions.cs index 2e59613d7c6..e02ff429fd6 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModelBuildingOptions.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/CollectionModelBuildingOptions.cs @@ -29,8 +29,10 @@ public sealed class CollectionModelBuildingOptions public bool UsesExternalSerializer { get; init; } /// - /// Gets the special, reserved name for the key property of the database. - /// When set, the model builder manages the key storage name, and users cannot customize it. + /// Gets or initializes the special, reserved name for the key property of the database. /// + /// + /// When set, the model builder manages the key storage name, and users cannot customize it. + /// public string? ReservedKeyStorageName { get; init; } } diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/KeyPropertyModel.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/KeyPropertyModel.cs index 6c4ef7357f4..d3e93bdc9f0 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/KeyPropertyModel.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/KeyPropertyModel.cs @@ -21,10 +21,12 @@ public class KeyPropertyModel(string modelName, Type type) : PropertyModel(model /// /// Gets or sets the name that the JSON serializer will produce for this key property. - /// This is needed for providers that use an external JSON serializer combined with a reserved key storage name - /// (e.g. CosmosDB NoSQL uses "id"): the serializer produces a JSON object with the policy-transformed name, and - /// the provider needs to find and replace it with the reserved storage name. /// + /// + /// This is needed for providers that use an external JSON serializer combined with a reserved key storage name + /// (for example, CosmosDB NoSQL uses "id"): the serializer produces a JSON object with the + /// policy-transformed name, and the provider needs to find and replace it with the reserved storage name. + /// public string? SerializedKeyName { get; set; } /// diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/PropertyModel.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/PropertyModel.cs index f9f25432b36..ca256affbf6 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/PropertyModel.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/ProviderServices/PropertyModel.cs @@ -21,13 +21,19 @@ public abstract class PropertyModel(string modelName, Type type) private Action? _setter; /// - /// Gets or sets the model name of the property. If the property corresponds to a .NET property, this name is the name of that property. + /// Gets or sets the model name of the property. /// + /// + /// If the property corresponds to a .NET property, this name is the name of that property. + /// public string ModelName { get; set; } = modelName; /// - /// Gets or sets the storage name of the property. This is the name to which the property is mapped in the vector store. + /// Gets or sets the storage name of the property. /// + /// + /// This is the name to which the property is mapped in the vector store. + /// public string StorageName { get => field ?? ModelName; @@ -57,11 +63,14 @@ public string StorageName public Dictionary? ProviderAnnotations { get; set; } /// - /// Gets a value indicating whether the property type is nullable. For value types, this is when the type is - /// . For reference types on .NET 6+, this uses NRT annotations via - /// NullabilityInfoContext when a is available - /// (i.e., POCO mapping); otherwise, reference types are assumed nullable. + /// Gets a value indicating whether the property type is nullable. /// + /// + /// For value types, this is when the type is . + /// For reference types on .NET 6+, this uses NRT annotations via NullabilityInfoContext + /// when a is available (that is, during POCO mapping); + /// otherwise, reference types are assumed nullable. + /// public bool IsNullable { get diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreCollectionMetadata.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreCollectionMetadata.cs index 60678df1c7b..4c65f8d4d5b 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreCollectionMetadata.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreCollectionMetadata.cs @@ -6,7 +6,7 @@ namespace Microsoft.Extensions.VectorData; /// Provides metadata about an . public class VectorStoreCollectionMetadata { - /// Gets the name of the vector store system. + /// Gets or initializes the name of the vector store system. /// /// Where possible, this value maps to the "db.system.name" attribute defined in the /// OpenTelemetry Semantic Conventions for database calls and systems; see . @@ -15,12 +15,12 @@ public class VectorStoreCollectionMetadata public string? VectorStoreSystemName { get; init; } /// - /// Gets the name of the vector store (database). + /// Gets or initializes the name of the vector store (database). /// public string? VectorStoreName { get; init; } /// - /// Gets the name of a collection (table, container) within the vector store (database). + /// Gets or initializes the name of a collection (table, container) within the vector store (database). /// public string? CollectionName { get; init; } } diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreException.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreException.cs index 9961f106569..32958c277ca 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreException.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreException.cs @@ -36,7 +36,7 @@ public VectorStoreException(string? message, Exception? innerException) { } - /// Gets the name of the vector store system. + /// Gets or initializes the name of the vector store system. /// /// Where possible, this value maps to the "db.system.name" attribute defined in the /// OpenTelemetry Semantic Conventions for database calls and systems; see . @@ -45,17 +45,17 @@ public VectorStoreException(string? message, Exception? innerException) public string? VectorStoreSystemName { get; init; } /// - /// Gets the name of the vector store (database). + /// Gets or initializes the name of the vector store (database). /// public string? VectorStoreName { get; init; } /// - /// Gets the name of the vector store collection that the failing operation was performed on. + /// Gets or initializes the name of the vector store collection that the failing operation was performed on. /// public string? CollectionName { get; init; } /// - /// Gets the name of the vector store operation that failed. + /// Gets or initializes the name of the vector store operation that failed. /// public string? OperationName { get; init; } } diff --git a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreMetadata.cs b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreMetadata.cs index 73091776eb9..6cdf0c57deb 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreMetadata.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.Abstractions/VectorStoreMetadata.cs @@ -15,7 +15,7 @@ public class VectorStoreMetadata public string? VectorStoreSystemName { get; init; } /// - /// Gets the name of the vector store (database). + /// Gets or initializes the name of the vector store (database). /// public string? VectorStoreName { get; init; } } diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/CollectionManagementTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/CollectionManagementTests.cs index ebaddb7ec35..f6ff4ed9de7 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/CollectionManagementTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/CollectionManagementTests.cs @@ -14,7 +14,7 @@ public Task InitializeAsync() => fixture.VectorStore.EnsureCollectionDeletedAsync(CollectionName); [Fact] - public async Task Collection_Ensure_Exists_Delete() + public virtual async Task Collection_Ensure_Exists_Delete() { var collection = GetCollection(); @@ -29,7 +29,7 @@ public async Task Collection_Ensure_Exists_Delete() } [Fact] - public async Task EnsureCollectionExists_twice_does_not_throw() + public virtual async Task EnsureCollectionExists_twice_does_not_throw() { var collection = GetCollection(); @@ -39,7 +39,7 @@ public async Task EnsureCollectionExists_twice_does_not_throw() } [Fact] - public async Task Store_CollectionExists() + public virtual async Task Store_CollectionExists() { var store = fixture.VectorStore; var collection = GetCollection(); @@ -50,7 +50,7 @@ public async Task Store_CollectionExists() } [Fact] - public async Task Store_DeleteCollection() + public virtual async Task Store_DeleteCollection() { var store = fixture.VectorStore; var collection = GetCollection(); @@ -61,7 +61,7 @@ public async Task Store_DeleteCollection() } [Fact] - public async Task Store_ListCollections() + public virtual async Task Store_ListCollections() { var store = fixture.VectorStore; var collection = GetCollection(); @@ -75,7 +75,7 @@ public async Task Store_ListCollections() } [Fact] - public void Collection_metadata() + public virtual void Collection_metadata() { var collection = GetCollection(); diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/DependencyInjectionTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/DependencyInjectionTests.cs index ae0aa1ab210..d7568d9192c 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/DependencyInjectionTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/DependencyInjectionTests.cs @@ -31,7 +31,7 @@ public abstract class DependencyInjectionTests> CollectionDelegates { get; } [Fact] - public void ServiceCollectionCantBeNull() + public virtual void ServiceCollectionCantBeNull() { foreach (var registrationDelegate in StoreDelegates) { @@ -47,7 +47,7 @@ public void ServiceCollectionCantBeNull() } [Fact] - public void CollectionNameCantBeNullOrEmpty() + public virtual void CollectionNameCantBeNullOrEmpty() { const string EmptyCollectionName = ""; @@ -84,7 +84,7 @@ public virtual void CanRegisterVectorStore(ServiceLifetime lifetime, object? ser [Theory] [MemberData(nameof(LifetimesAndServiceKeys))] - public void CanRegisterCollections(ServiceLifetime lifetime, object? serviceKey) + public virtual void CanRegisterCollections(ServiceLifetime lifetime, object? serviceKey) { foreach (var registrationDelegate in CollectionDelegates) { @@ -136,7 +136,7 @@ public virtual void CanRegisterConcreteTypeVectorStoreAfterSomeAbstractionHasBee [Theory] [MemberData(nameof(LifetimesAndServiceKeys))] - public void CanRegisterConcreteTypeCollectionsAfterSomeAbstractionHasBeenRegistered(ServiceLifetime lifetime, object? serviceKey) + public virtual void CanRegisterConcreteTypeCollectionsAfterSomeAbstractionHasBeenRegistered(ServiceLifetime lifetime, object? serviceKey) { foreach (var registrationDelegate in CollectionDelegates) { @@ -156,7 +156,7 @@ public void CanRegisterConcreteTypeCollectionsAfterSomeAbstractionHasBeenRegiste [Theory] [MemberData(nameof(LifetimesAndServiceKeys))] - public void EmbeddingGeneratorIsResolved(ServiceLifetime lifetime, object? serviceKey) + public virtual void EmbeddingGeneratorIsResolved(ServiceLifetime lifetime, object? serviceKey) { foreach (var registrationDelegate in CollectionDelegates) { diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/HybridSearchTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/HybridSearchTests.cs index 44f64188ca8..6fd4ce6587c 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/HybridSearchTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/HybridSearchTests.cs @@ -17,7 +17,7 @@ public abstract class HybridSearchTests( where TKey : notnull { [Fact] - public async Task HybridSearchAsync() + public virtual async Task HybridSearchAsync() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -33,7 +33,7 @@ public async Task HybridSearchAsync() } [Fact] - public async Task HybridSearchAsync_with_filter() + public virtual async Task HybridSearchAsync_with_filter() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -54,7 +54,7 @@ public async Task HybridSearchAsync_with_filter() } [Fact] - public async Task HybridSearchAsync_with_top() + public virtual async Task HybridSearchAsync_with_top() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -71,7 +71,7 @@ public async Task HybridSearchAsync_with_top() } [Fact] - public async Task HybridSearchAsync_with_Skip() + public virtual async Task HybridSearchAsync_with_Skip() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -88,7 +88,7 @@ public async Task HybridSearchAsync_with_Skip() } [Fact] - public async Task HybridSearchAsync_with_multiple_keywords_ranks_matched_keywords_higher() + public virtual async Task HybridSearchAsync_with_multiple_keywords_ranks_matched_keywords_higher() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -105,7 +105,7 @@ public async Task HybridSearchAsync_with_multiple_keywords_ranks_matched_keyword } [Fact] - public async Task HybridSearchAsync_with_multiple_text_properties() + public virtual async Task HybridSearchAsync_with_multiple_text_properties() { // Arrange var vector = new ReadOnlyMemory([1, 0, 0, 0]); @@ -131,7 +131,7 @@ public async Task HybridSearchAsync_with_multiple_text_properties() } [Fact] - public Task HybridSearchAsync_without_explicitly_specified_property_fails() + public virtual Task HybridSearchAsync_without_explicitly_specified_property_fails() => Assert.ThrowsAsync(async () => await multiTextFixture.HybridSearchable .HybridSearchAsync(new ReadOnlyMemory([1, 0, 0, 0]), ["Apples"], top: 3) diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs index 48ba8be4b90..8d13ec8fceb 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/ModelTests/DynamicModelTests.cs @@ -284,7 +284,7 @@ public virtual async Task Insert_multiple_records() #region Delete [Fact] - public async Task Delete_single_record() + public virtual async Task Delete_single_record() { var recordToRemove = fixture.TestData[2]; diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/TestStore.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/TestStore.cs index e8ec5215f66..98b3c28b1f4 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/TestStore.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/TestStore.cs @@ -16,13 +16,13 @@ public abstract class TestStore private VectorStore? _defaultVectorStore; /// - /// Some databases modify vectors on upsert, e.g. normalizing them, so vectors - /// returned cannot be compared with the original ones. + /// Gets a value indicating whether vectors returned from the database can be + /// compared with the original vectors. /// public virtual bool VectorsComparable => true; /// - /// Whether the database supports filtering by score threshold in vector search. + /// Gets a value indicating whether the database supports filtering by score threshold in vector search. /// public virtual bool SupportsScoreThreshold => true; @@ -95,8 +95,10 @@ public virtual string AdjustCollectionName(string baseName) /// /// Creates a collection for the given name and definition. - /// Override this to provide provider-specific collection options (e.g., partition key configuration). /// + /// + /// Override this to provide provider-specific collection options, such as partition key configuration. + /// public virtual VectorStoreCollection CreateCollection( string name, VectorStoreCollectionDefinition definition) @@ -106,8 +108,10 @@ public virtual VectorStoreCollection CreateCollection /// Creates a dynamic collection for the given name and definition. - /// Override this to provide provider-specific collection options (e.g., partition key configuration). /// + /// + /// Override this to provide provider-specific collection options, such as partition key configuration. + /// public virtual VectorStoreCollection> CreateDynamicCollection( string name, VectorStoreCollectionDefinition definition) diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs index 1caf31ef99a..ec2ce898629 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreCollectionFixtureBase.cs @@ -25,7 +25,7 @@ public abstract class VectorStoreCollectionFixtureBase : VectorSt protected abstract string CollectionNameBase { get; } /// - /// The actual name of the test collection, after any provider-specific collection naming rules have been applied. + /// Gets the actual name of the test collection after any provider-specific collection naming rules have been applied. /// public virtual string CollectionName => TestStore.AdjustCollectionName(CollectionNameBase); diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreFixture.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreFixture.cs index 5702abce498..9c7a1002abb 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreFixture.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/Support/VectorStoreFixture.cs @@ -27,8 +27,10 @@ public virtual TKey GenerateNextKey() /// /// Creates a collection for the given name and definition. - /// Delegates to which can be overridden for provider-specific options. /// + /// + /// This delegates to , which can be overridden for provider-specific options. + /// public virtual VectorStoreCollection CreateCollection(string name, VectorStoreCollectionDefinition definition) where TKey : notnull where TRecord : class @@ -36,8 +38,10 @@ public virtual VectorStoreCollection CreateCollection /// Creates a dynamic collection for the given name and definition. - /// Delegates to which can be overridden for provider-specific options. /// + /// + /// This delegates to , which can be overridden for provider-specific options. + /// public virtual VectorStoreCollection> CreateDynamicCollection(string name, VectorStoreCollectionDefinition definition) => TestStore.CreateDynamicCollection(name, definition); } diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/DataTypeTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/DataTypeTests.cs index e6f0c992ced..bdc99a62d52 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/DataTypeTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/DataTypeTests.cs @@ -440,9 +440,11 @@ public abstract class Fixture : VectorStoreCollectionFixture private readonly IList _defaultDataProperties; /// - /// Whether the recreate the collection while testing, as opposed to deleting the records. - /// Necessary for InMemory, where the .NET mapped on the collection cannot be changed. + /// Gets a value indicating whether the collection is recreated while testing instead of deleting the records. /// + /// + /// This is necessary for InMemory, where the .NET type mapped on the collection cannot be changed. + /// public virtual bool RecreateCollection => false; #pragma warning disable CA2214 // Do not call overridable methods in constructors diff --git a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/EmbeddingTypeTests.cs b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/EmbeddingTypeTests.cs index 941151734dc..ee9bc56fb90 100644 --- a/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/EmbeddingTypeTests.cs +++ b/src/Libraries/Microsoft.Extensions.VectorData.ConformanceTests/TypeTests/EmbeddingTypeTests.cs @@ -242,16 +242,20 @@ public virtual VectorStoreCollectionDefinition CreateRecordDefinition - /// Whether the recreate the collection while testing, as opposed to deleting the records. - /// Necessary for InMemory, where the .NET mapped on the collection cannot be changed. + /// Gets a value indicating whether the collection is recreated while testing instead of deleting the records. /// + /// + /// This is necessary for InMemory, where the .NET type mapped on the collection cannot be changed. + /// public virtual bool RecreateCollection => false; /// - /// Whether to assert that no vectors were loaded when embedding generation is used. - /// Necessary for InMemory which returns the same object which was inserted, and therefore contains - /// the original input value. + /// Gets a value indicating whether to assert that no vectors were loaded when embedding generation is used. /// + /// + /// Asserting that no vectors were loaded is necessary for InMemory, which returns the same object that was inserted and therefore contains + /// the original input value. + /// public virtual bool AssertNoVectorsLoadedWithEmbeddingGeneration => true; } } diff --git a/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.csproj b/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.csproj index acce7a15d8a..afbfd93c4b7 100644 --- a/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.csproj +++ b/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.csproj @@ -10,7 +10,7 @@ 1 - 3 + 13 0 preview diff --git a/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/templates/AIAgentWebApi-CSharp/.template.config/template.json b/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/templates/AIAgentWebApi-CSharp/.template.config/template.json index e61d1a68614..b534bdc52be 100644 --- a/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/templates/AIAgentWebApi-CSharp/.template.config/template.json +++ b/src/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates/templates/AIAgentWebApi-CSharp/.template.config/template.json @@ -1,7 +1,7 @@ { "$schema": "http://json.schemastore.org/template", "author": "Microsoft", - "classifications": [ "Common", "AI", "API", "Web", "Web API", "WebAPI", "Service" ], + "classifications": [ "Common", "AI", "API", "Web", "Web API", "Service" ], "identity": "Microsoft.Agents.AI.ProjectTemplates.AIAgentWebApi.CSharp", "name": "AI Agent Web API", "description": "A project template for creating an AI Agent Web API application.", diff --git a/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/templates/AIChatWeb-CSharp/AIChatWeb-CSharp.AppHost/AIChatWeb-CSharp.AppHost.csproj-in b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/templates/AIChatWeb-CSharp/AIChatWeb-CSharp.AppHost/AIChatWeb-CSharp.AppHost.csproj-in index efaf93c8114..ca38328d28e 100644 --- a/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/templates/AIChatWeb-CSharp/AIChatWeb-CSharp.AppHost/AIChatWeb-CSharp.AppHost.csproj-in +++ b/src/ProjectTemplates/Microsoft.Extensions.AI.Templates/templates/AIChatWeb-CSharp/AIChatWeb-CSharp.AppHost/AIChatWeb-CSharp.AppHost.csproj-in @@ -12,6 +12,7 @@ + - + - + + diff --git a/src/Shared/DiagnosticIds/DiagnosticIds.cs b/src/Shared/DiagnosticIds/DiagnosticIds.cs index e2615f0a0bb..abddbf61c5a 100644 --- a/src/Shared/DiagnosticIds/DiagnosticIds.cs +++ b/src/Shared/DiagnosticIds/DiagnosticIds.cs @@ -53,6 +53,8 @@ internal static class Experiments internal const string AITextToSpeech = AIExperiments; internal const string AIMcpServers = AIExperiments; internal const string AIFunctionApprovals = AIExperiments; + internal const string AIApprovalsInvocationRequired = AIExperiments; + internal const string AIFunctionAndParameterName = AIExperiments; internal const string AIChatReduction = AIExperiments; internal const string AIToolSearch = AIExperiments; diff --git a/test/Directory.Build.props b/test/Directory.Build.props index f886872fa3d..4b7a330f474 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,12 +2,22 @@ false - $(NoWarn);RT0000 + + $(NoWarn);RT0000;xUnit1051 + + XUnitV3 + + Exe + + true $(LatestTargetFramework) + ;net472 diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 8cddc800bac..90c365d89e9 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,6 +1,11 @@ + + $(MSBuildThisFileDirectory)\..\eng\xunit.runner.json + $(MSBuildThisFileDirectory)\..\eng\xunit.runner.json + + @@ -8,10 +13,20 @@ - + - - + + + + $(TargetFramework) + + + diff --git a/test/Generators/Microsoft.Gen.ComplianceReports/Unit/GeneratorTests.cs b/test/Generators/Microsoft.Gen.ComplianceReports/Unit/GeneratorTests.cs index 28dbb80a36c..490ae645e16 100644 --- a/test/Generators/Microsoft.Gen.ComplianceReports/Unit/GeneratorTests.cs +++ b/test/Generators/Microsoft.Gen.ComplianceReports/Unit/GeneratorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -12,7 +12,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Gen.Shared; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Gen.ComplianceReports.Tests; diff --git a/test/Generators/Microsoft.Gen.ContextualOptions/Generated/Microsoft.Gen.ContextualOptions.Generated.Tests.csproj b/test/Generators/Microsoft.Gen.ContextualOptions/Generated/Microsoft.Gen.ContextualOptions.Generated.Tests.csproj index e99de5a9789..8fb859be613 100644 --- a/test/Generators/Microsoft.Gen.ContextualOptions/Generated/Microsoft.Gen.ContextualOptions.Generated.Tests.csproj +++ b/test/Generators/Microsoft.Gen.ContextualOptions/Generated/Microsoft.Gen.ContextualOptions.Generated.Tests.csproj @@ -5,8 +5,7 @@ - $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) true true true diff --git a/test/Generators/Microsoft.Gen.Logging/Generated/Microsoft.Gen.Logging.Generated.Tests.csproj b/test/Generators/Microsoft.Gen.Logging/Generated/Microsoft.Gen.Logging.Generated.Tests.csproj index d4a72e9e371..78615f29b9b 100644 --- a/test/Generators/Microsoft.Gen.Logging/Generated/Microsoft.Gen.Logging.Generated.Tests.csproj +++ b/test/Generators/Microsoft.Gen.Logging/Generated/Microsoft.Gen.Logging.Generated.Tests.csproj @@ -5,8 +5,7 @@ - $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) true true true diff --git a/test/Generators/Microsoft.Gen.Logging/HelperLibrary/Microsoft.Gen.Logging.HelperLibrary.csproj b/test/Generators/Microsoft.Gen.Logging/HelperLibrary/Microsoft.Gen.Logging.HelperLibrary.csproj index 0f3e6d3bedf..19ccc382efb 100644 --- a/test/Generators/Microsoft.Gen.Logging/HelperLibrary/Microsoft.Gen.Logging.HelperLibrary.csproj +++ b/test/Generators/Microsoft.Gen.Logging/HelperLibrary/Microsoft.Gen.Logging.HelperLibrary.csproj @@ -2,11 +2,12 @@ Microsoft.Gen.Logging.Test Test classes for Microsoft.Gen.Logging.Generated.Tests. + Library + false - $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) diff --git a/test/Generators/Microsoft.Gen.MetadataExtractor/Unit/GeneratorTests.cs b/test/Generators/Microsoft.Gen.MetadataExtractor/Unit/GeneratorTests.cs index 6d7f9a23c61..18554b46b91 100644 --- a/test/Generators/Microsoft.Gen.MetadataExtractor/Unit/GeneratorTests.cs +++ b/test/Generators/Microsoft.Gen.MetadataExtractor/Unit/GeneratorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -15,7 +15,6 @@ using Microsoft.Extensions.Logging; using Microsoft.Gen.Shared; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Gen.MetadataExtractor.Unit.Tests; diff --git a/test/Generators/Microsoft.Gen.Metrics/Generated/Microsoft.Gen.Metrics.Generated.Tests.csproj b/test/Generators/Microsoft.Gen.Metrics/Generated/Microsoft.Gen.Metrics.Generated.Tests.csproj index 114e45e0df7..c7a2e0fa99b 100644 --- a/test/Generators/Microsoft.Gen.Metrics/Generated/Microsoft.Gen.Metrics.Generated.Tests.csproj +++ b/test/Generators/Microsoft.Gen.Metrics/Generated/Microsoft.Gen.Metrics.Generated.Tests.csproj @@ -5,8 +5,7 @@ - $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) true true $(NoWarn);IDE0161;S1144 diff --git a/test/Generators/Microsoft.Gen.MetricsReports/Unit/GeneratorTests.cs b/test/Generators/Microsoft.Gen.MetricsReports/Unit/GeneratorTests.cs index f432257b111..55ee834ee31 100644 --- a/test/Generators/Microsoft.Gen.MetricsReports/Unit/GeneratorTests.cs +++ b/test/Generators/Microsoft.Gen.MetricsReports/Unit/GeneratorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -14,7 +14,6 @@ using Microsoft.Extensions.Diagnostics.Metrics; using Microsoft.Gen.Shared; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Gen.MetricsReports.Test; diff --git a/test/Libraries/Directory.Build.props b/test/Libraries/Directory.Build.props index d64d3a34c2c..0cbaf696fbc 100644 --- a/test/Libraries/Directory.Build.props +++ b/test/Libraries/Directory.Build.props @@ -3,6 +3,6 @@ $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) diff --git a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakeCertificateFactoryTests.cs b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakeCertificateFactoryTests.cs index 1da6dc74ddc..b7236129359 100644 --- a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakeCertificateFactoryTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakeCertificateFactoryTests.cs @@ -1,10 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Linq; +using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.AspNetCore.Testing.Test; @@ -23,19 +23,21 @@ public void Create_CreatesCertificate() Assert.False(certificate.Extensions.OfType().Single().Critical); } - [ConditionalTheory] - [OSSkipCondition(OperatingSystems.Linux)] + [Theory] [InlineData(false)] [InlineData(true)] public void GenerateRsa_RunsOnWindows_GeneratesRsa(bool runsOnWindows) { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Linux"); + Assert.NotNull(FakeSslCertificateFactory.GenerateRsa(runsOnWindows)); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows)] + [Fact] public void GenerateRsa_DoesNotRunOnWindows_GeneratesRsa() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Windows"); + Assert.NotNull(FakeSslCertificateFactory.GenerateRsa(runsOnWindows: false)); } } diff --git a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakesExtensionsTests.cs b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakesExtensionsTests.cs index 668b0730c1a..7f8e689ed48 100644 --- a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakesExtensionsTests.cs +++ b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/FakesExtensionsTests.cs @@ -108,6 +108,7 @@ public void CreateClient_NoAddress_Throws() var exception = Record.Exception(() => hostMock.Object.CreateClient(null, _ => false)); + Assert.NotNull(exception); Assert.IsType(exception); Assert.Equal("No suitable address found to call the server.", exception.Message); } @@ -119,6 +120,7 @@ public void CreateClient_NoSuitableAddress_Throws() var exception = Record.Exception(() => hostMock.Object.CreateClient(null, _ => false)); + Assert.NotNull(exception); Assert.IsType(exception); Assert.Equal("No suitable address found to call the server.", exception.Message); } diff --git a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/Microsoft.AspNetCore.Testing.Tests.csproj b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/Microsoft.AspNetCore.Testing.Tests.csproj index 11d60ebbaba..934d3750f68 100644 --- a/test/Libraries/Microsoft.AspNetCore.Testing.Tests/Microsoft.AspNetCore.Testing.Tests.csproj +++ b/test/Libraries/Microsoft.AspNetCore.Testing.Tests/Microsoft.AspNetCore.Testing.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.AspNetCore.Testing.Test Unit tests for Microsoft.AspNetCore.Testing @@ -11,6 +11,5 @@ - diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.FSharp.Tests/Microsoft.Extensions.AI.Abstractions.FSharp.Tests.fsproj b/test/Libraries/Microsoft.Extensions.AI.Abstractions.FSharp.Tests/Microsoft.Extensions.AI.Abstractions.FSharp.Tests.fsproj index dfaf0f0c5d9..75d94804a8f 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Abstractions.FSharp.Tests/Microsoft.Extensions.AI.Abstractions.FSharp.Tests.fsproj +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.FSharp.Tests/Microsoft.Extensions.AI.Abstractions.FSharp.Tests.fsproj @@ -7,13 +7,19 @@ true - $(NoWarn);FS3261 + + $(NoWarn);FS3261;FS0052 + + + + + diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs index 8111bf80e94..bab1f9f4f68 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs @@ -50,6 +50,7 @@ public static void EqualMessageLists(List expectedMessages, List(json, AIJsonUtilities.DefaultOptions); + + Assert.NotNull(deserialized); + Assert.Equal(value, deserialized!.RequiresConfirmation); + } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AINameAttributesTests.cs b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AINameAttributesTests.cs new file mode 100644 index 00000000000..ec439f4885c --- /dev/null +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Functions/AINameAttributesTests.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Xunit; + +namespace Microsoft.Extensions.AI; + +public class AINameAttributesTests +{ + [Fact] + public void AIFunctionNameAttribute_InvalidArguments_Throw() + { + Assert.Throws("name", () => new AIFunctionNameAttribute(null!)); + Assert.Throws("name", () => new AIFunctionNameAttribute(" ")); + } + + [Fact] + public void AIParameterNameAttribute_InvalidArguments_Throw() + { + Assert.Throws("name", () => new AIParameterNameAttribute(null!)); + Assert.Throws("name", () => new AIParameterNameAttribute(" ")); + } +} diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Microsoft.Extensions.AI.Abstractions.Tests.csproj b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Microsoft.Extensions.AI.Abstractions.Tests.csproj index 2a1dfe36c6d..f2b8c40018a 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Microsoft.Extensions.AI.Abstractions.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Microsoft.Extensions.AI.Abstractions.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.AI Unit tests for Microsoft.Extensions.AI.Abstractions. @@ -37,6 +37,5 @@ - diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs index 606fdea9721..9039dc6a385 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -15,10 +15,10 @@ using System.Text.Json.Serialization.Metadata; using System.Threading; using Microsoft.Extensions.AI.JsonSchemaExporter; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable SA1114 // parameter list should follow declaration +#pragma warning disable S1144 // Unused private types or members should be removed (members are used via reflection in schema tests) namespace Microsoft.Extensions.AI; @@ -563,6 +563,25 @@ static void TestMethod(int x, int y) Assert.Equal("Method description", descElement.GetString()); } + [Fact] + public static void CreateFunctionJsonSchema_AIFunctionNameAttribute_NotUsedForTitle() + { + MethodInfo method = ((Action)MethodWithAIFunctionName).Method; + JsonElement schema = AIJsonUtilities.CreateFunctionJsonSchema(method); + + // The schema title is derived from the method name, not from AIFunctionNameAttribute. + Assert.True(schema.TryGetProperty("title", out JsonElement titleElement)); + Assert.Equal(nameof(MethodWithAIFunctionName), titleElement.GetString()); + Assert.NotEqual("my_tool", titleElement.GetString()); + } + + // Local functions get unspeakable names; define as a private method instead. + [AIFunctionName("my_tool")] + private static void MethodWithAIFunctionName() + { + // Test method for schema generation + } + [Fact] public static void CreateFunctionJsonSchema_DisplayNameAttribute_CanBeOverridden() { @@ -580,6 +599,63 @@ static void TestMethod() Assert.Equal("override_title", titleElement.GetString()); } + [Fact] + public static void CreateFunctionJsonSchema_AIParameterNameAttribute_UsedForPropertyName() + { + static void TestMethod([AIParameterName("custom_property_name")] string select, int top) + { + // Test method for schema generation + } + + var method = ((Action)TestMethod).Method; + JsonElement schema = AIJsonUtilities.CreateFunctionJsonSchema(method); + + JsonElement properties = schema.GetProperty("properties"); + Assert.True(properties.TryGetProperty("custom_property_name", out _)); + Assert.False(properties.TryGetProperty("select", out _)); + + string[] required = schema.GetProperty("required").EnumerateArray().Select(e => e.GetString()!).ToArray(); + Assert.Contains("custom_property_name", required); + Assert.Contains("top", required); + } + + [Fact] + public static void CreateFunctionJsonSchema_AIParameterNameAttribute_DuplicateNamesThrow() + { + static void DuplicateByAttribute([AIParameterName("dup")] string first, [AIParameterName("dup")] string second) + { + // Test method for schema generation + } + + ArgumentException ex = Assert.Throws(() => AIJsonUtilities.CreateFunctionJsonSchema(((Action)DuplicateByAttribute).Method)); + Assert.Contains("dup", ex.Message); + Assert.Equal("method", ex.ParamName); + + static void DuplicateByCollision([AIParameterName("filter")] string select, string filter) + { + // Test method for schema generation + } + + ArgumentException ex2 = Assert.Throws(() => AIJsonUtilities.CreateFunctionJsonSchema(((Action)DuplicateByCollision).Method)); + Assert.Contains("filter", ex2.Message); + Assert.Equal("method", ex2.ParamName); + } + + [Fact] + public static void CreateFunctionJsonSchema_AIParameterNameAttribute_EscapesJsonPointerSegment() + { + JsonSerializerOptions options = new() { TypeInfoResolver = new DefaultJsonTypeInfoResolver() }; + static void TestMethod([AIParameterName("a/b~c")] RecursiveNode node) + { + // Test method for schema generation + } + + string schema = AIJsonUtilities.CreateFunctionJsonSchema(((Action)TestMethod).Method, serializerOptions: options).ToString(); + + Assert.Contains("#/properties/a~1b~0c", schema); + Assert.DoesNotContain("#/properties/a/b~c", schema); + } + [Fact] public static void CreateJsonSchema_CanBeBoolean() { @@ -648,13 +724,10 @@ public static void CreateJsonSchema_NullableEnum_IncludesTypeKeyword() AssertDeepEquals(expectedSchema, schema); } - [ConditionalFact] + [Fact] public static void CreateJsonSchema_IncorporatesTypesAndAnnotations_Net() { - if (RuntimeInformation.FrameworkDescription.Contains(".NET Framework")) - { - return; - } + Assert.SkipUnless(!RuntimeInformation.FrameworkDescription.Contains(".NET Framework"), "Only runs on .NET Core"); AssertDeepEquals(JsonSerializer.Deserialize( """ @@ -884,13 +957,10 @@ public static void CreateJsonSchema_IncorporatesTypesAndAnnotations_Net() // .NET Framework only has a subset of the available data annotation attributes. // .NET Standard doesn't have any (the M.E.AI.Abstractions library doesn't reference the additional package). - [ConditionalFact] + [Fact] public static void CreateJsonSchema_IncorporatesTypesAndAnnotations_NetFx() { - if (!RuntimeInformation.FrameworkDescription.Contains(".NET Framework")) - { - return; - } + Assert.SkipUnless(RuntimeInformation.FrameworkDescription.Contains(".NET Framework"), "Only runs on .NET Framework"); AssertDeepEquals(JsonSerializer.Deserialize( """ @@ -1862,6 +1932,11 @@ public DerivedToolCallContent() public int CustomValue { get; set; } } + private sealed class RecursiveNode + { + public RecursiveNode? Next { get; set; } + } + [JsonSerializable(typeof(JsonElement))] [JsonSerializable(typeof(CreateJsonSchema_IncorporatesTypesAndAnnotations_Type))] [JsonSerializable(typeof(DerivedAIContent))] diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/AgentQualityEvaluatorTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/AgentQualityEvaluatorTests.cs index 238b805e867..f8b908dbf55 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/AgentQualityEvaluatorTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/AgentQualityEvaluatorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -11,7 +11,6 @@ using Microsoft.Extensions.AI.Evaluation.Reporting; using Microsoft.Extensions.AI.Evaluation.Reporting.Storage; using Microsoft.Extensions.AI.Evaluation.Tests; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Integration.Tests; @@ -81,7 +80,7 @@ static AgentQualityEvaluatorTests() } } - [ConditionalFact] + [Fact] public async Task ToolDefinitionsAreNotNeededAndNotPassed() { SkipIfNotConfigured(); @@ -104,7 +103,7 @@ await _agentQualityReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(IntentResolutionEvaluator.IntentResolutionMetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task ToolDefinitionsAreNotNeededButPassed() { SkipIfNotConfigured(); @@ -137,7 +136,7 @@ await scenarioRun.EvaluateAsync( Assert.True(result.TryGet(IntentResolutionEvaluator.IntentResolutionMetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task ToolDefinitionsAreNeededButNotPassed() { SkipIfNotConfigured(); @@ -161,7 +160,7 @@ await _needsContextReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(IntentResolutionEvaluator.IntentResolutionMetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task ToolDefinitionsAreNeededAndPassed() { SkipIfNotConfigured(); @@ -268,10 +267,7 @@ private record OrderStatus(int OrderId, string Status, DateTime ExpectedDelivery [MemberNotNull(nameof(_needsContextReportingConfiguration))] private static void SkipIfNotConfigured() { - if (!Settings.Current.Configured) - { - throw new SkipTestException("Test is not configured"); - } + Assert.SkipUnless(Settings.Current.Configured, "Test is not configured"); Assert.NotNull(_chatOptionsWithTools); Assert.NotNull(_agentQualityReportingConfiguration); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/Microsoft.Extensions.AI.Evaluation.Integration.Tests.csproj b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/Microsoft.Extensions.AI.Evaluation.Integration.Tests.csproj index 579debd599f..9f7215dd25b 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/Microsoft.Extensions.AI.Evaluation.Integration.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/Microsoft.Extensions.AI.Evaluation.Integration.Tests.csproj @@ -1,4 +1,4 @@ - + $(LatestTargetFramework) @@ -34,7 +34,6 @@ - \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/NLPEvaluatorTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/NLPEvaluatorTests.cs index 9cd593a647a..857af1e21fd 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/NLPEvaluatorTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/NLPEvaluatorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -8,7 +8,6 @@ using Microsoft.Extensions.AI.Evaluation.NLP; using Microsoft.Extensions.AI.Evaluation.Reporting; using Microsoft.Extensions.AI.Evaluation.Reporting.Storage; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Integration.Tests; @@ -41,7 +40,7 @@ static NLPEvaluatorTests() } } - [ConditionalFact] + [Fact] public async Task ExactMatch() { SkipIfNotConfigured(); @@ -67,7 +66,7 @@ await _nlpReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(F1Evaluator.F1MetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task PartialMatch() { SkipIfNotConfigured(); @@ -94,7 +93,7 @@ await _nlpReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(F1Evaluator.F1MetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task Unmatched() { SkipIfNotConfigured(); @@ -120,7 +119,7 @@ await _nlpReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(F1Evaluator.F1MetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task AdditionalContextIsNotPassed() { SkipIfNotConfigured(); @@ -149,10 +148,7 @@ await _nlpReportingConfiguration.CreateScenarioRunAsync( [MemberNotNull(nameof(_nlpReportingConfiguration))] private static void SkipIfNotConfigured() { - if (!Settings.Current.Configured) - { - throw new SkipTestException("Test is not configured"); - } + Assert.SkipUnless(Settings.Current.Configured, "Test is not configured"); Assert.NotNull(_nlpReportingConfiguration); } diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/QualityEvaluatorTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/QualityEvaluatorTests.cs index fde342a4161..7dbb56c0e2f 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/QualityEvaluatorTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/QualityEvaluatorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -10,7 +10,6 @@ using Microsoft.Extensions.AI.Evaluation.Reporting; using Microsoft.Extensions.AI.Evaluation.Reporting.Storage; using Microsoft.Extensions.AI.Evaluation.Tests; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Integration.Tests; @@ -74,7 +73,7 @@ static QualityEvaluatorTests() } } - [ConditionalFact] + [Fact] public async Task SampleSingleResponse() { SkipIfNotConfigured(); @@ -107,7 +106,7 @@ await _qualityReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(RelevanceEvaluator.RelevanceMetricName, out NumericMetric? _)); } - [ConditionalFact] + [Fact] public async Task SampleMultipleResponses() { SkipIfNotConfigured(); @@ -153,7 +152,7 @@ await _qualityReportingConfiguration.CreateScenarioRunAsync( #endif } - [ConditionalFact] + [Fact] public async Task AdditionalContextIsNotPassed() { SkipIfNotConfigured(); @@ -188,7 +187,7 @@ await _needsContextReportingConfiguration.CreateScenarioRunAsync( Assert.Null(retrieval.Context); } - [ConditionalFact] + [Fact] public async Task AdditionalContextIsPassed() { SkipIfNotConfigured(); @@ -282,10 +281,7 @@ await scenarioRun.EvaluateAsync( [MemberNotNull(nameof(_needsContextReportingConfiguration))] private static void SkipIfNotConfigured() { - if (!Settings.Current.Configured) - { - throw new SkipTestException("Test is not configured"); - } + Assert.SkipUnless(Settings.Current.Configured, "Test is not configured"); Assert.NotNull(_chatOptions); Assert.NotNull(_qualityReportingConfiguration); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/SafetyEvaluatorTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/SafetyEvaluatorTests.cs index 68b4a9d8ce0..8d13756aaa8 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/SafetyEvaluatorTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Integration.Tests/SafetyEvaluatorTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -13,7 +13,6 @@ using Microsoft.Extensions.AI.Evaluation.Safety; using Microsoft.Extensions.AI.Evaluation.Tests; using Microsoft.Extensions.AI.Evaluation.Utilities; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Integration.Tests; @@ -154,7 +153,7 @@ static SafetyEvaluatorTests() } } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithSingleTurn_HubBasedProject() { SkipIfNotConfigured(); @@ -166,7 +165,7 @@ await _hubBasedContentSafetyReportingConfiguration.CreateScenarioRunAsync( await EvaluateConversationWithSingleTurn(scenarioRun); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithSingleTurn_NonHubBasedProject() { SkipIfNotConfigured(); @@ -232,7 +231,7 @@ The distance varies due to the elliptical orbits of both planets. ReferenceEquals(context2, ungroundedAttributesContext)); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithMultipleTurns_HubBasedProject() { SkipIfNotConfigured(); @@ -244,7 +243,7 @@ await _hubBasedContentSafetyReportingConfiguration.CreateScenarioRunAsync( await EvaluateConversationWithMultipleTurns(scenarioRun); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithMultipleTurns_NonHubBasedProject() { SkipIfNotConfigured(); @@ -323,7 +322,7 @@ At its furthest (conjunction), it can be approximately 601 million miles away. ReferenceEquals(context2, ungroundedAttributesContext)); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithImageInQuestion() { SkipIfNotConfigured(); @@ -359,7 +358,7 @@ await _imageContentSafetyReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(IndirectAttackEvaluator.IndirectAttackMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithImageInAnswer() { SkipIfNotConfigured(); @@ -395,7 +394,7 @@ await _imageContentSafetyReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(IndirectAttackEvaluator.IndirectAttackMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithImagesInMultipleTurns() { SkipIfNotConfigured(); @@ -444,7 +443,7 @@ await _imageContentSafetyReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(IndirectAttackEvaluator.IndirectAttackMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateConversationWithImagesAndTextInMultipleTurns() { SkipIfNotConfigured(); @@ -506,7 +505,7 @@ These distances are approximate and can vary slightly depending on the specific Assert.True(result.TryGet(IndirectAttackEvaluator.IndirectAttackMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateCodeCompletionWithSingleTurn() { SkipIfNotConfigured(); @@ -535,7 +534,7 @@ await _codeVulnerabilityReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(CodeVulnerabilityEvaluator.CodeVulnerabilityMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateCodeCompletionWithMultipleTurns() { SkipIfNotConfigured(); @@ -576,7 +575,7 @@ await _codeVulnerabilityReportingConfiguration.CreateScenarioRunAsync( Assert.True(result.TryGet(CodeVulnerabilityEvaluator.CodeVulnerabilityMetricName, out BooleanMetric? _)); } - [ConditionalFact] + [Fact] public async Task EvaluateSafetyAndQualityMetricsForSameConversation() { SkipIfNotConfigured(); @@ -622,10 +621,7 @@ await _mixedQualityAndSafetyReportingConfiguration.CreateScenarioRunAsync( [MemberNotNull(nameof(_hubBasedContentSafetyReportingConfiguration))] private static void SkipIfNotConfigured() { - if (!Settings.Current.Configured) - { - throw new SkipTestException("Test is not configured"); - } + Assert.SkipUnless(Settings.Current.Configured, "Test is not configured"); Assert.NotNull(_chatOptions); Assert.NotNull(_contentSafetyReportingConfiguration); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResponseCacheTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResponseCacheTests.cs index 2f936621147..ad7b460f0dc 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResponseCacheTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResponseCacheTests.cs @@ -35,10 +35,18 @@ public AzureResponseCacheTests() _dirClient = _fsClient?.GetDirectoryClient(Path.GetRandomFileName()); } - public Task InitializeAsync() => Task.CompletedTask; + public ValueTask InitializeAsync() + { +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif + } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { + GC.SuppressFinalize(this); if (Settings.Current.Configured) { await CreateResponseCacheProvider().ResetAsync(); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResultStoreTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResultStoreTests.cs index 62163d5e681..375a58bb8ac 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResultStoreTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/AzureStorage/AzureResultStoreTests.cs @@ -35,10 +35,18 @@ public AzureResultStoreTests() _dirClient = _fsClient?.GetDirectoryClient(Path.GetRandomFileName()); } - public Task InitializeAsync() => Task.CompletedTask; + public ValueTask InitializeAsync() + { +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif + } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { + GC.SuppressFinalize(this); if (_dirClient is not null) { await _dirClient.DeleteAsync(); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResponseCacheTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResponseCacheTests.cs index 8305fe8ddb3..4e188343099 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResponseCacheTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResponseCacheTests.cs @@ -22,10 +22,18 @@ private string UseTempStoragePath() return path; } - public Task InitializeAsync() => Task.CompletedTask; + public ValueTask InitializeAsync() + { +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif + } - public Task DisposeAsync() + public ValueTask DisposeAsync() { + GC.SuppressFinalize(this); foreach (string path in _tempStorage) { try @@ -40,7 +48,11 @@ public Task DisposeAsync() } } - return Task.CompletedTask; +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif } internal override bool IsConfigured => true; diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResultStoreTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResultStoreTests.cs index 77cabfd7ffd..184ed9d922a 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResultStoreTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/DiskBasedResultStoreTests.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; @@ -21,10 +22,18 @@ private string UseTempStoragePath() return path; } - public Task InitializeAsync() => Task.CompletedTask; + public ValueTask InitializeAsync() + { +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif + } - public Task DisposeAsync() + public ValueTask DisposeAsync() { + GC.SuppressFinalize(this); foreach (string path in _tempStorage) { try @@ -39,7 +48,11 @@ public Task DisposeAsync() } } - return Task.CompletedTask; +#if NET + return ValueTask.CompletedTask; +#else + return new ValueTask(Task.CompletedTask); +#endif } public override bool IsConfigured => true; diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/PathValidationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/PathValidationTests.cs index bcf7dceaa3d..9b47d0404cb 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/PathValidationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/DiskBased/PathValidationTests.cs @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.AI.Evaluation.Reporting.Utilities; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Reporting.Tests; @@ -257,10 +256,11 @@ await Assert.ThrowsAsync(() => // EnsureWithinRoot – UNC paths (Windows only) // ────────────────────────────────────────────── - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_UncPath_ChildPath_ReturnsResolved() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"\\server\share\data"; string child = @"\\server\share\data\sub\file.txt"; @@ -269,10 +269,11 @@ public void EnsureWithinRoot_UncPath_ChildPath_ReturnsResolved() Assert.Equal(Path.GetFullPath(child), result); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_UncPath_DifferentShare_Throws() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"\\server\share\data"; string other = @"\\server\share\other\file.txt"; @@ -280,10 +281,11 @@ public void EnsureWithinRoot_UncPath_DifferentShare_Throws() PathValidation.EnsureWithinRoot(root, other)); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_UncPath_DotDotEscapes_Throws() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"\\server\share\data"; string escaped = @"\\server\share\data\..\other"; @@ -291,10 +293,11 @@ public void EnsureWithinRoot_UncPath_DotDotEscapes_Throws() PathValidation.EnsureWithinRoot(root, escaped)); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_UncPath_SiblingWithPrefix_Throws() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"\\server\share\data"; string sibling = @"\\server\share\data-sibling\file.txt"; @@ -302,10 +305,11 @@ public void EnsureWithinRoot_UncPath_SiblingWithPrefix_Throws() PathValidation.EnsureWithinRoot(root, sibling)); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_UncPath_PathEqualsRoot_DoesNotThrow() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"\\server\share\data"; string result = PathValidation.EnsureWithinRoot(root, root); @@ -317,10 +321,11 @@ public void EnsureWithinRoot_UncPath_PathEqualsRoot_DoesNotThrow() // EnsureWithinRoot – short (8.3) Windows paths // ────────────────────────────────────────────── - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_ShortPathRoot_LongPathChild_DocumentedBehavior() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + // Short (8.3) paths are NOT consistently normalized by Path.GetFullPath // across .NET versions. This test documents that if the root uses a short // path form and the child uses the long form, the behavior depends on @@ -365,10 +370,11 @@ public void EnsureWithinRoot_ShortPathRoot_LongPathChild_DocumentedBehavior() } } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_ConsistentShortPaths_Works() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + // When both root and child are constructed from the same short-path // string via Path.Combine, EnsureWithinRoot succeeds because // Path.GetFullPath treats both consistently. @@ -403,10 +409,11 @@ public void EnsureWithinRoot_ConsistentShortPaths_Works() // EnsureWithinRoot – additional edge cases // ────────────────────────────────────────────── - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_AltSeparatorInRoot_Works() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + // Forward slash is an alternate directory separator on Windows. string root = Path.GetTempPath().Replace('\\', '/') + "testroot"; string child = Path.Combine(root, "sub", "file.txt"); @@ -436,10 +443,11 @@ public void EnsureWithinRoot_CaseMismatch_BehavesPerPlatform() } } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_DriveRoot_ChildPath_Works() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"C:\"; string child = @"C:\some\nested\file.txt"; @@ -448,10 +456,11 @@ public void EnsureWithinRoot_DriveRoot_ChildPath_Works() Assert.Equal(Path.GetFullPath(child), result); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + [Fact] public void EnsureWithinRoot_DriveRoot_DifferentDrive_Throws() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + string root = @"C:\data"; string other = @"D:\data\file.txt"; @@ -459,10 +468,11 @@ public void EnsureWithinRoot_DriveRoot_DifferentDrive_Throws() PathValidation.EnsureWithinRoot(root, other)); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows)] + [Fact] public void EnsureWithinRoot_UnixAbsoluteRoot_ChildPath_Works() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Windows"); + string root = "/tmp/testroot"; string child = "/tmp/testroot/sub/file.txt"; diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/EmbeddingTests.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/EmbeddingTests.cs index bf00efc6471..fddd07ba7df 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/EmbeddingTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/EmbeddingTests.cs @@ -1,23 +1,19 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.Extensions.AI.Evaluation.Reporting.Formats.Html; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Reporting.Tests; public class EmbeddingTests { - [ConditionalFact] + [Fact] public void CIBuildsMustIncludeEmbeddedHTML() { // TF_BUILD should be set in our CI pipeline - if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TF_BUILD"))) - { - throw new SkipTestException("Skipping test because it is not running in CI"); - } + Assert.SkipUnless(!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TF_BUILD")), "Skipping test because it is not running in CI"); Assert.NotEmpty(HtmlReportWriter.HtmlTemplateBefore); Assert.NotEmpty(HtmlReportWriter.HtmlTemplateAfter); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/Microsoft.Extensions.AI.Evaluation.Reporting.Tests.csproj b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/Microsoft.Extensions.AI.Evaluation.Reporting.Tests.csproj index 44b7e2f561b..b29f0f64373 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/Microsoft.Extensions.AI.Evaluation.Reporting.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/Microsoft.Extensions.AI.Evaluation.Reporting.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.AI.Evaluation.Reporting.Tests @@ -17,7 +17,6 @@ - - \ No newline at end of file + diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs index 50793dfdb66..328379094eb 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResponseCacheTester.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Reporting.Tests; @@ -23,13 +22,10 @@ public abstract class ResponseCacheTester private void SkipIfNotConfigured() { - if (!IsConfigured) - { - throw new SkipTestException("Test not configured"); - } + Assert.SkipUnless(IsConfigured, "Test not configured"); } - [ConditionalFact] + [Fact] public async Task AddUncachedEntry() { SkipIfNotConfigured(); @@ -52,7 +48,7 @@ public async Task AddUncachedEntry() Assert.True(_responseB.SequenceEqual(cached)); } - [ConditionalFact] + [Fact] public async Task RemoveCachedEntry() { SkipIfNotConfigured(); @@ -78,7 +74,7 @@ public async Task RemoveCachedEntry() Assert.Null(cache.Get(_keyB)); } - [ConditionalFact] + [Fact] public async Task CacheEntryExpiration() { SkipIfNotConfigured(); @@ -106,7 +102,7 @@ public async Task CacheEntryExpiration() Assert.Null(cache.Get(_keyB)); } - [ConditionalFact] + [Fact] public async Task MultipleCacheInstances() { SkipIfNotConfigured(); @@ -128,7 +124,7 @@ public async Task MultipleCacheInstances() Assert.True(_responseB.SequenceEqual(cache.Get(_keyB) ?? [])); } - [ConditionalFact] + [Fact] public async Task DeleteExpiredEntries() { SkipIfNotConfigured(); @@ -163,7 +159,7 @@ public async Task DeleteExpiredEntries() Assert.Null(cache.Get(_keyB)); } - [ConditionalFact] + [Fact] public async Task ResetCache() { SkipIfNotConfigured(); diff --git a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResultStoreTester.cs b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResultStoreTester.cs index 995b77a8c5e..12504cd2a47 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResultStoreTester.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting.Tests/ResultStoreTester.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,7 +6,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.AI.Evaluation.Reporting.Tests; @@ -59,13 +58,10 @@ private static ScenarioRunResult CreateTestResult(string scenarioName, string it private void SkipIfNotConfigured() { - if (!IsConfigured) - { - throw new SkipTestException("Test not configured"); - } + Assert.SkipUnless(IsConfigured, "Test not configured"); } - [ConditionalFact] + [Fact] public async Task WriteAndReadResults() { SkipIfNotConfigured(); @@ -104,7 +100,7 @@ public async Task WriteAndReadResults() Assert.Equal(IterationName(5), results[5].iterationName); } - [ConditionalFact] + [Fact] public async Task WriteAndReadHistoricalResults() { SkipIfNotConfigured(); @@ -148,7 +144,7 @@ public async Task WriteAndReadHistoricalResults() Assert.True(results.Skip(6).Take(3).All(r => r.executionName == firstExecutionName)); } - [ConditionalFact] + [Fact] public async Task DeleteExecutions() { SkipIfNotConfigured(); @@ -172,7 +168,7 @@ public async Task DeleteExecutions() Assert.Empty(results); } - [ConditionalFact] + [Fact] public async Task DeleteSomeExecutions() { SkipIfNotConfigured(); @@ -207,7 +203,7 @@ public async Task DeleteSomeExecutions() Assert.Equal(IterationName(5), results[2].iterationName); } - [ConditionalFact] + [Fact] public async Task DeleteScenarios() { SkipIfNotConfigured(); @@ -242,7 +238,7 @@ public async Task DeleteScenarios() Assert.Equal(IterationName(5), results[2].iterationName); } - [ConditionalFact] + [Fact] public async Task DeleteIterations() { SkipIfNotConfigured(); diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs index 208fbddf34f..75bed1ef82e 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ChatClientIntegrationTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -18,7 +18,6 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; -using Microsoft.TestUtilities; using OpenTelemetry.Trace; using Xunit; @@ -49,7 +48,7 @@ public void Dispose() protected abstract IChatClient? CreateChatClient(); - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_SingleRequestMessage() { SkipIfNotEnabled(); @@ -59,7 +58,7 @@ public virtual async Task GetResponseAsync_SingleRequestMessage() Assert.Contains("whale", response.Text, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_MultipleRequestMessages() { SkipIfNotEnabled(); @@ -77,7 +76,7 @@ public virtual async Task GetResponseAsync_MultipleRequestMessages() Assert.Contains("Asia", response.Text); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_WithEmptyMessage() { SkipIfNotEnabled(); @@ -93,7 +92,7 @@ public virtual async Task GetResponseAsync_WithEmptyMessage() Assert.Contains("3", response.Text); } - [ConditionalFact] + [Fact] public virtual async Task GetStreamingResponseAsync() { SkipIfNotEnabled(); @@ -114,7 +113,7 @@ public virtual async Task GetStreamingResponseAsync() Assert.Contains("one giant leap", responseText, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_UsageDataAvailable() { SkipIfNotEnabled(); @@ -126,7 +125,7 @@ public virtual async Task GetResponseAsync_UsageDataAvailable() Assert.Equal(response.Usage?.InputTokenCount + response.Usage?.OutputTokenCount, response.Usage?.TotalTokenCount); } - [ConditionalFact] + [Fact] public virtual async Task GetStreamingResponseAsync_UsageDataAvailable() { SkipIfNotEnabled(); @@ -153,7 +152,7 @@ public virtual async Task GetStreamingResponseAsync_UsageDataAvailable() Assert.Equal(usage.Details.InputTokenCount + usage.Details.OutputTokenCount, usage.Details.TotalTokenCount); } - [ConditionalFact] + [Fact] public virtual async Task GetStreamingResponseAsync_AppendToHistory() { SkipIfNotEnabled(); @@ -174,7 +173,7 @@ public virtual async Task GetStreamingResponseAsync_AppendToHistory() protected virtual string? GetModel_MultiModal_DescribeImage() => null; - [ConditionalFact] + [Fact] public virtual async Task MultiModal_DescribeImage() { SkipIfNotEnabled(); @@ -192,7 +191,7 @@ public virtual async Task MultiModal_DescribeImage() Assert.True(response.Text.IndexOf("net", StringComparison.OrdinalIgnoreCase) >= 0, response.Text); } - [ConditionalFact] + [Fact] public virtual async Task MultiModal_DescribePdf() { SkipIfNotEnabled(); @@ -210,7 +209,7 @@ public virtual async Task MultiModal_DescribePdf() Assert.True(response.Text.IndexOf("hello", StringComparison.OrdinalIgnoreCase) >= 0, response.Text); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_Parameterless() { SkipIfNotEnabled(); @@ -241,7 +240,7 @@ public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_Paramet AssertUsageAgainstActivities(response, activities); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_WithParameters_NonStreaming() { SkipIfNotEnabled(); @@ -256,7 +255,7 @@ public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_WithPar Assert.Contains("3528", response.Text); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_WithParameters_Streaming() { SkipIfNotEnabled(); @@ -277,7 +276,7 @@ public virtual async Task FunctionInvocation_AutomaticallyInvokeFunction_WithPar Assert.Contains("3528", sb.ToString()); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_OptionalParameter() { SkipIfNotEnabled(); @@ -309,7 +308,7 @@ public virtual async Task FunctionInvocation_OptionalParameter() AssertUsageAgainstActivities(response, activities); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_NestedParameters() { SkipIfNotEnabled(); @@ -341,7 +340,7 @@ public virtual async Task FunctionInvocation_NestedParameters() AssertUsageAgainstActivities(response, activities); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_ArrayParameter() { SkipIfNotEnabled(); @@ -391,11 +390,11 @@ private static void AssertUsageAgainstActivities(ChatResponse response, List AvailableTools_SchemasAreAccepted(strict: true); - [ConditionalFact] + [Fact] public virtual Task AvailableTools_SchemasAreAccepted_NonStrict() => AvailableTools_SchemasAreAccepted(strict: false); @@ -562,14 +561,11 @@ private class ComplexObject protected virtual bool SupportsParallelFunctionCalling => true; - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_SupportsMultipleParallelRequests() { SkipIfNotEnabled(); - if (!SupportsParallelFunctionCalling) - { - throw new SkipTestException("Parallel function calling is not supported by this chat client"); - } + Assert.SkipUnless(SupportsParallelFunctionCalling, "Parallel function calling is not supported by this chat client"); using var chatClient = new FunctionInvokingChatClient(ChatClient); @@ -592,7 +588,7 @@ public virtual async Task FunctionInvocation_SupportsMultipleParallelRequests() $"Doesn't contain three: {response.Text}"); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_RequireAny() { SkipIfNotEnabled(); @@ -615,7 +611,7 @@ public virtual async Task FunctionInvocation_RequireAny() Assert.True(callCount >= 1); } - [ConditionalFact] + [Fact] public virtual async Task FunctionInvocation_RequireSpecific() { SkipIfNotEnabled(); @@ -636,7 +632,7 @@ public virtual async Task FunctionInvocation_RequireSpecific() Assert.True(shieldsUp); } - [ConditionalFact] + [Fact] public virtual async Task Caching_OutputVariesWithoutCaching() { SkipIfNotEnabled(); @@ -648,7 +644,7 @@ public virtual async Task Caching_OutputVariesWithoutCaching() Assert.NotEqual(firstResponse.Text, secondResponse.Text); } - [ConditionalFact] + [Fact] public virtual async Task Caching_SamePromptResultsInCacheHit_NonStreaming() { SkipIfNotEnabled(); @@ -673,7 +669,7 @@ public virtual async Task Caching_SamePromptResultsInCacheHit_NonStreaming() Assert.NotEqual(firstResponse.Messages, thirdResponse.Messages); } - [ConditionalFact] + [Fact] public virtual async Task Caching_SamePromptResultsInCacheHit_Streaming() { SkipIfNotEnabled(); @@ -712,7 +708,7 @@ public virtual async Task Caching_SamePromptResultsInCacheHit_Streaming() Assert.NotEqual(orig.ToString(), third.ToString()); } - [ConditionalFact] + [Fact] public virtual async Task Caching_BeforeFunctionInvocation_AvoidsExtraCalls() { SkipIfNotEnabled(); @@ -748,7 +744,7 @@ public virtual async Task Caching_BeforeFunctionInvocation_AvoidsExtraCalls() Assert.Equal(2, llmCallCount!.CallCount); } - [ConditionalFact] + [Fact] public virtual async Task Caching_AfterFunctionInvocation_FunctionOutputUnchangedAsync() { SkipIfNotEnabled(); @@ -790,7 +786,7 @@ public virtual async Task Caching_AfterFunctionInvocation_FunctionOutputUnchange public virtual bool FunctionInvokingChatClientSetsConversationId => false; - [ConditionalFact] + [Fact] public virtual async Task Caching_AfterFunctionInvocation_FunctionOutputChangedAsync() { SkipIfNotEnabled(); @@ -831,7 +827,7 @@ public virtual async Task Caching_AfterFunctionInvocation_FunctionOutputChangedA Assert.Equal(3, llmCallCount!.CallCount); } - [ConditionalFact] + [Fact] public virtual async Task Logging_LogsCalls_NonStreaming() { SkipIfNotEnabled(); @@ -850,7 +846,7 @@ public virtual async Task Logging_LogsCalls_NonStreaming() entry => Assert.Contains("whale", entry.Message)); } - [ConditionalFact] + [Fact] public virtual async Task Logging_LogsCalls_Streaming() { SkipIfNotEnabled(); @@ -872,7 +868,7 @@ public virtual async Task Logging_LogsCalls_Streaming() Assert.Contains(logs, e => e.Message.Contains("whale")); } - [ConditionalFact] + [Fact] public virtual async Task Logging_LogsFunctionCalls_NonStreaming() { SkipIfNotEnabled(); @@ -898,7 +894,7 @@ await chatClient.GetResponseAsync( entry => Assert.Contains(secretNumber.ToString(), entry.Message)); } - [ConditionalFact] + [Fact] public virtual async Task Logging_LogsFunctionCalls_Streaming() { SkipIfNotEnabled(); @@ -926,7 +922,7 @@ public virtual async Task Logging_LogsFunctionCalls_Streaming() Assert.Contains(logs, e => e.Message.Contains($"\"result\": {secretNumber}")); } - [ConditionalFact] + [Fact] public virtual async Task OpenTelemetry_CanEmitTracesAndMetrics() { SkipIfNotEnabled(); @@ -956,7 +952,7 @@ public virtual async Task OpenTelemetry_CanEmitTracesAndMetrics() Assert.True(activity.Duration.TotalMilliseconds > 0); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutput() { SkipIfNotEnabled(); @@ -972,7 +968,7 @@ Who is described in the following sentence? Assert.Equal(JobType.Programmer, response.Result.Job); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputArray() { SkipIfNotEnabled(); @@ -988,7 +984,7 @@ Who are described in the following sentence? Assert.Contains(response.Result, x => x.FullName == "Josh Simpson"); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputInteger() { SkipIfNotEnabled(); @@ -1001,7 +997,7 @@ To fix this we added another one. How many are there now? Assert.Equal(15, response.Result); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputString() { SkipIfNotEnabled(); @@ -1014,7 +1010,7 @@ public virtual async Task GetResponseAsync_StructuredOutputString() Assert.Equal("Jimbo Smith", response.Result); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputBool_True() { SkipIfNotEnabled(); @@ -1027,7 +1023,7 @@ Is there at least one software developer from Cardiff? Assert.True(response.Result); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputBool_False() { SkipIfNotEnabled(); @@ -1040,7 +1036,7 @@ public virtual async Task GetResponseAsync_StructuredOutputBool_False() Assert.False(response.Result); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutputEnum() { SkipIfNotEnabled(); @@ -1052,7 +1048,7 @@ Taylor Swift is a famous singer and songwriter. What is her job? Assert.Equal(JobType.PopStar, response.Result); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutput_WithFunctions() { SkipIfNotEnabled(); @@ -1083,7 +1079,7 @@ public virtual async Task GetResponseAsync_StructuredOutput_WithFunctions() Assert.Equal(expectedPerson.Job, response.Result.Job); } - [ConditionalFact] + [Fact] public virtual async Task GetResponseAsync_StructuredOutput_NonNative() { SkipIfNotEnabled(); @@ -1129,7 +1125,7 @@ private enum JobType Unknown, } - [ConditionalFact] + [Fact] public virtual async Task SummarizingChatReducer_PreservesConversationContext() { SkipIfNotEnabled(); @@ -1171,7 +1167,7 @@ public virtual async Task SummarizingChatReducer_PreservesConversationContext() $"Expected 'hiking' or 'hike' in response: {response.Text}"); } - [ConditionalFact] + [Fact] public virtual async Task SummarizingChatReducer_PreservesSystemMessage() { SkipIfNotEnabled(); @@ -1215,7 +1211,7 @@ public virtual async Task SummarizingChatReducer_PreservesSystemMessage() $"Expected pirate speak in response: {response.Text}"); } - [ConditionalFact] + [Fact] public virtual async Task SummarizingChatReducer_WithFunctionCalls() { SkipIfNotEnabled(); @@ -1266,7 +1262,7 @@ public virtual async Task SummarizingChatReducer_WithFunctionCalls() $"Expected weather comparison in response: {response.Text}"); } - [ConditionalFact] + [Fact] public virtual async Task SummarizingChatReducer_Streaming() { SkipIfNotEnabled(); @@ -1311,7 +1307,7 @@ public virtual async Task SummarizingChatReducer_Streaming() $"Expected 'software' or 'engineer' in response: {responseText}"); } - [ConditionalFact] + [Fact] public virtual async Task SummarizingChatReducer_CustomPrompt() { SkipIfNotEnabled(); @@ -1405,10 +1401,7 @@ protected void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || ChatClient is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && ChatClient is not null, "Client is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/EmbeddingGeneratorIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/EmbeddingGeneratorIntegrationTests.cs index 20423ae9e8b..72f0ef894ed 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/EmbeddingGeneratorIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/EmbeddingGeneratorIntegrationTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -16,7 +16,6 @@ using System.Threading.Tasks; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; -using Microsoft.TestUtilities; using OpenTelemetry.Trace; using Xunit; @@ -42,7 +41,7 @@ public void Dispose() protected abstract IEmbeddingGenerator>? CreateEmbeddingGenerator(); - [ConditionalFact] + [Fact] public virtual async Task GenerateEmbedding_CreatesEmbeddingSuccessfully() { SkipIfNotEnabled(); @@ -57,7 +56,7 @@ public virtual async Task GenerateEmbedding_CreatesEmbeddingSuccessfully() Assert.NotEmpty(embeddings[0].Vector.ToArray()); } - [ConditionalFact] + [Fact] public virtual async Task GenerateEmbeddings_CreatesEmbeddingsSuccessfully() { SkipIfNotEnabled(); @@ -79,7 +78,7 @@ public virtual async Task GenerateEmbeddings_CreatesEmbeddingsSuccessfully() }); } - [ConditionalFact] + [Fact] public virtual async Task Caching_SameOutputsForSameInput() { SkipIfNotEnabled(); @@ -102,7 +101,7 @@ public virtual async Task Caching_SameOutputsForSameInput() Assert.Equal(2, callCounter.CallCount); } - [ConditionalFact] + [Fact] public virtual async Task OpenTelemetry_CanEmitTracesAndMetrics() { SkipIfNotEnabled(); @@ -134,7 +133,7 @@ public virtual async Task OpenTelemetry_CanEmitTracesAndMetrics() } #if NET - [ConditionalFact] + [Fact] public async Task Quantization_Binary_EmbeddingsCompareSuccessfully() { SkipIfNotEnabled(); @@ -178,7 +177,7 @@ static byte[] ToArray(BitArray array) Assert.True(distances[2, 3] < distances[1, 3]); } - [ConditionalFact] + [Fact] public async Task Quantization_Half_EmbeddingsCompareSuccessfully() { SkipIfNotEnabled(); @@ -219,9 +218,6 @@ public async Task Quantization_Half_EmbeddingsCompareSuccessfully() [MemberNotNull(nameof(_embeddingGenerator))] protected void SkipIfNotEnabled() { - if (_embeddingGenerator is null) - { - throw new SkipTestException("Generator is not enabled."); - } + Assert.SkipUnless(_embeddingGenerator is not null, "Generator is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratingChatClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratingChatClientIntegrationTests.cs index 2cbdcd96abf..80c66c5a5f0 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratingChatClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratingChatClientIntegrationTests.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable CA2000 // Dispose objects before losing scope @@ -111,7 +110,7 @@ static ChatResponse ValidateChatResponse(ChatResponse response) } } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task GenerateImage_CallsGenerateFunction_ReturnsDataContent(bool useStreaming) @@ -147,7 +146,7 @@ [new ChatMessage(ChatRole.User, "Please generate an image of a cat")], Assert.False(imageContent.Data.IsEmpty); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task EditImage_WithImageInSameRequest_PassesExactDataContent(bool useStreaming) @@ -178,7 +177,7 @@ [new ChatMessage(ChatRole.User, [new TextContent("Please edit this image to add Assert.Equal("original.png", originalImageContent.Name); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task GenerateThenEdit_FromChatHistory_EditsGeneratedImage(bool useStreaming) @@ -228,7 +227,7 @@ public virtual async Task GenerateThenEdit_FromChatHistory_EditsGeneratedImage(b Assert.Contains("generated_image_1", editedImage.Name); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task MultipleEdits_EditsLatestImage(bool useStreaming) @@ -273,7 +272,7 @@ public virtual async Task MultipleEdits_EditsLatestImage(bool useStreaming) Assert.Equal(secondImage, lastImageToEdit); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task MultipleEdits_EditsFirstImage(bool useStreaming) @@ -318,7 +317,7 @@ public virtual async Task MultipleEdits_EditsFirstImage(bool useStreaming) Assert.Equal(firstGeneratedImage, lastImageToEdit); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task ImageGeneration_WithOptions_PassesOptionsToGenerator(bool useStreaming) @@ -350,7 +349,7 @@ [new ChatMessage(ChatRole.User, "Generate an image of a castle")], Assert.Equal(new System.Drawing.Size(512, 512), options.ImageSize); } - [ConditionalTheory] + [Theory] [InlineData(false)] // Non-streaming [InlineData(true)] // Streaming public virtual async Task ImageContentHandling_AllImages_ReplacesImagesWithPlaceholders(bool useStreaming) @@ -440,9 +439,6 @@ protected void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || ChatClient is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && ChatClient is not null, "Client is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratorIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratorIntegrationTests.cs index 76b08941bc5..d7fb16aa2d5 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratorIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/ImageGeneratorIntegrationTests.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable CA2214 // Do not call overridable methods in constructors @@ -29,7 +28,7 @@ public void Dispose() protected abstract IImageGenerator? CreateGenerator(); - [ConditionalFact] + [Fact] public virtual async Task GenerateImagesAsync_SingleImageGeneration() { SkipIfNotEnabled(); @@ -62,7 +61,7 @@ public virtual async Task GenerateImagesAsync_SingleImageGeneration() } } - [ConditionalFact] + [Fact] public virtual async Task GenerateImagesAsync_MultipleImages() { SkipIfNotEnabled(); @@ -87,7 +86,7 @@ public virtual async Task GenerateImagesAsync_MultipleImages() } } - [ConditionalFact] + [Fact] public virtual async Task EditImagesAsync_SingleImage() { SkipIfNotEnabled(); @@ -127,9 +126,6 @@ protected void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || _generator is null) - { - throw new SkipTestException("Generator is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && _generator is not null, "Generator is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Microsoft.Extensions.AI.Integration.Tests.csproj b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Microsoft.Extensions.AI.Integration.Tests.csproj index ed657f5e2b6..379ed7f04b9 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Microsoft.Extensions.AI.Integration.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Microsoft.Extensions.AI.Integration.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.AI Opt-in integration tests for Microsoft.Extensions.AI. @@ -20,12 +20,28 @@ + + + + Never + + Never + + + Never + + + Never + + + Never + @@ -55,6 +71,5 @@ - diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.m4a b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.m4a new file mode 100644 index 00000000000..a082110afce Binary files /dev/null and b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.m4a differ diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.wav b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.wav new file mode 100644 index 00000000000..9b655bb88e1 Binary files /dev/null and b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.wav differ diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.webm b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.webm new file mode 100644 index 00000000000..98309fa200b Binary files /dev/null and b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001.webm differ diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001_noid3.mp3 b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001_noid3.mp3 new file mode 100644 index 00000000000..9ef9e9378dc Binary files /dev/null and b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/Resources/audio001_noid3.mp3 differ diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/SpeechToTextClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/SpeechToTextClientIntegrationTests.cs index f0ea6c1790e..d6f6f38e8e7 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/SpeechToTextClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/SpeechToTextClientIntegrationTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,7 +6,6 @@ using System.IO; using System.Text; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable CA2214 // Do not call overridable methods in constructors @@ -30,7 +29,7 @@ public void Dispose() protected abstract ISpeechToTextClient? CreateClient(); - [ConditionalFact] + [Fact] public virtual async Task GetTextAsync_SingleAudioRequestMessage() { SkipIfNotEnabled(); @@ -41,7 +40,7 @@ public virtual async Task GetTextAsync_SingleAudioRequestMessage() Assert.Contains("gym", response.Text, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public virtual async Task GetStreamingTextAsync_SingleStreamingResponseChoice() { SkipIfNotEnabled(); @@ -59,6 +58,23 @@ public virtual async Task GetStreamingTextAsync_SingleStreamingResponseChoice() Assert.Contains("gym", responseText, StringComparison.OrdinalIgnoreCase); } + [Theory] + [InlineData("audio001.mp3")] + [InlineData("audio001_noid3.mp3")] + [InlineData("audio001.wav")] + [InlineData("audio001.m4a")] + [InlineData("audio001.webm")] + public virtual async Task GetTextAsync_AutoDetectsAudioFormat(string fileName) + { + SkipIfNotEnabled(); + + using var audioSpeechStream = GetAudioStream(fileName); + var response = await _client.GetTextAsync(audioSpeechStream); + + Assert.NotNull(response); + Assert.Contains("gym", response.Text, StringComparison.OrdinalIgnoreCase); + } + private static Stream GetAudioStream(string fileName) { using Stream? s = typeof(SpeechToTextClientIntegrationTests).Assembly.GetManifestResourceStream($"Microsoft.Extensions.AI.Resources.{fileName}"); @@ -75,9 +91,6 @@ protected void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || _client is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && _client is not null, "Client is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/TextToSpeechClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/TextToSpeechClientIntegrationTests.cs index 823a225052a..c7ff72ab8ac 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/TextToSpeechClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/TextToSpeechClientIntegrationTests.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable CA2214 // Do not call overridable methods in constructors @@ -29,7 +28,7 @@ public void Dispose() protected abstract ITextToSpeechClient? CreateClient(); - [ConditionalFact] + [Fact] public virtual async Task GetAudioAsync_SimpleText_ReturnsAudio() { SkipIfNotEnabled(); @@ -45,7 +44,7 @@ public virtual async Task GetAudioAsync_SimpleText_ReturnsAudio() Assert.StartsWith("audio/", dataContent.MediaType, StringComparison.Ordinal); } - [ConditionalFact] + [Fact] public virtual async Task GetAudioAsync_WithVoice_ReturnsAudio() { SkipIfNotEnabled(); @@ -64,7 +63,7 @@ public virtual async Task GetAudioAsync_WithVoice_ReturnsAudio() Assert.StartsWith("audio/", dataContent.MediaType, StringComparison.Ordinal); } - [ConditionalFact] + [Fact] public virtual async Task GetAudioAsync_WithAudioFormat_ReturnsCorrectMediaType() { SkipIfNotEnabled(); @@ -83,7 +82,7 @@ public virtual async Task GetAudioAsync_WithAudioFormat_ReturnsCorrectMediaType( Assert.Equal("audio/opus", dataContent.MediaType); } - [ConditionalFact] + [Fact] public virtual async Task GetAudioAsync_WithSpeed_ReturnsAudio() { SkipIfNotEnabled(); @@ -101,7 +100,7 @@ public virtual async Task GetAudioAsync_WithSpeed_ReturnsAudio() Assert.False(dataContent.Data.IsEmpty); } - [ConditionalFact] + [Fact] public virtual async Task GetStreamingAudioAsync_SimpleText_ReturnsUpdates() { SkipIfNotEnabled(); @@ -130,9 +129,6 @@ protected void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || _client is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && _client is not null, "Client is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/VerbatimMultiPartHttpHandler.cs b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/VerbatimMultiPartHttpHandler.cs index 6b0374d70cd..77267476e28 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/VerbatimMultiPartHttpHandler.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Integration.Tests/VerbatimMultiPartHttpHandler.cs @@ -41,6 +41,8 @@ public class VerbatimMultiPartHttpHandler(string expectedInput, string sentJsonO { public string? ExpectedRequestUriContains { get; init; } + public string? ExpectedAudioFilename { get; init; } + protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) @@ -111,8 +113,16 @@ protected override async Task SendAsync( // Text field string name = ExtractNameFromHeaders(headers); - // Skip file fields - if (!name.StartsWith("file")) + // For file fields, optionally check the filename + if (name.StartsWith("file")) + { + if (ExpectedAudioFilename is not null) + { + string? actualFilename = ExtractFilenameFromHeaders(headers); + Assert.Equal(ExpectedAudioFilename, actualFilename); + } + } + else { if (parameters.ContainsKey(name)) { @@ -185,6 +195,25 @@ private static string ExtractNameFromHeaders(string headers) return headers.Substring(start, end - start).Trim('"'); } + private static string? ExtractFilenameFromHeaders(string headers) + { + const string FilenamePrefix = "filename="; + int start = headers.IndexOf(FilenamePrefix); + if (start < 0) + { + return null; + } + + start += FilenamePrefix.Length; + int end = headers.IndexOf(";", start); + if (end == -1) + { + end = headers.Length; + } + + return headers.Substring(start, end - start).Trim('"'); + } + public static string? RemoveWhiteSpace(string? text) => text is null ? null : Regex.Replace(text, @"\s*", string.Empty); diff --git a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests.csproj b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests.csproj index 6eb7259d3f6..d977c035279 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests.csproj @@ -13,8 +13,6 @@ - - diff --git a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/NotAllTestsAreSkippedTests.cs b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/NotAllTestsAreSkippedTests.cs new file mode 100644 index 00000000000..3f3e062cfe3 --- /dev/null +++ b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/NotAllTestsAreSkippedTests.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace Microsoft.Extensions.AI; + +/// +/// We need this test to ensure that not all tests in this project are skipped. +/// When all tests are skipped, Microsoft.Testing.Platform exits with code 8 ("zero tests ran") +/// which is treated as a failure in CI. This test guarantees at least one test always executes. +/// +public class NotAllTestsAreSkippedTests +{ + [Fact] + public void NotAllTestsAreSkipped() + { + if (TestRunnerConfiguration.Instance["Ollama:Endpoint"] is string endpoint) + { + Assert.NotNull(IntegrationTestHelpers.GetOllamaUri()); + } + } +} diff --git a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpChatClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpChatClientIntegrationTests.cs index 28d3e21fd65..8ed29b756a7 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpChatClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpChatClientIntegrationTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,7 +6,6 @@ using System.ComponentModel; using System.Threading; using System.Threading.Tasks; -using Microsoft.TestUtilities; using OllamaSharp; using Xunit; @@ -19,15 +18,17 @@ public class OllamaSharpChatClientIntegrationTests : ChatClientIntegrationTests new OllamaApiClient(endpoint, "llama3.2") : null; - public override Task FunctionInvocation_RequireAny() => - throw new SkipTestException("Ollama does not currently support requiring function invocation."); + public override Task FunctionInvocation_RequireAny() + { + Assert.Skip("Ollama does not currently support requiring function invocation."); + return Task.CompletedTask; // Unreachable + } - public override Task FunctionInvocation_RequireSpecific() => - throw new SkipTestException("Ollama does not currently support requiring function invocation."); + public override Task FunctionInvocation_RequireSpecific() => FunctionInvocation_RequireAny(); protected override string? GetModel_MultiModal_DescribeImage() => "llava"; - [ConditionalFact] + [Fact] public async Task PromptBasedFunctionCalling_NoArgs() { SkipIfNotEnabled(); @@ -51,7 +52,7 @@ public async Task PromptBasedFunctionCalling_NoArgs() Assert.Contains(secretNumber.ToString(), response.Text); } - [ConditionalFact] + [Fact] public async Task PromptBasedFunctionCalling_WithArgs() { SkipIfNotEnabled(); @@ -86,7 +87,7 @@ public async Task PromptBasedFunctionCalling_WithArgs() Assert.False(didCallIrrelevantTool); } - [ConditionalFact] + [Fact] public async Task InvalidModelParameter_ThrowsInvalidOperationException() { SkipIfNotEnabled(); diff --git a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpEmbeddingGeneratorIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpEmbeddingGeneratorIntegrationTests.cs index f7775143c36..42310d93467 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpEmbeddingGeneratorIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OllamaSharp.Integration.Tests/OllamaSharpEmbeddingGeneratorIntegrationTests.cs @@ -1,9 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Threading.Tasks; -using Microsoft.TestUtilities; using OllamaSharp; using Xunit; @@ -16,7 +15,7 @@ public class OllamaSharpEmbeddingGeneratorIntegrationTests : EmbeddingGeneratorI new OllamaApiClient(endpoint, "all-minilm") : null; - [ConditionalFact] + [Fact] public async Task InvalidModelParameter_ThrowsInvalidOperationException() { SkipIfNotEnabled(); diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIAssistantChatClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIAssistantChatClientIntegrationTests.cs index 15f0ebcb73c..70f127982f2 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIAssistantChatClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIAssistantChatClientIntegrationTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable CA1822 // Mark members as static @@ -12,7 +12,6 @@ using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Microsoft.TestUtilities; using OpenAI.Assistants; using Xunit; @@ -48,7 +47,7 @@ public class OpenAIAssistantChatClientIntegrationTests : ChatClientIntegrationTe public override Task MultiModal_DescribeImage() => Task.CompletedTask; public override Task MultiModal_DescribePdf() => Task.CompletedTask; - [ConditionalFact] + [Fact] public async Task UseCodeInterpreter_ProducesCodeExecutionResults() { SkipIfNotEnabled(); diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIHostedFileClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIHostedFileClientIntegrationTests.cs index 2cf739d6427..ec0736550f6 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIHostedFileClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIHostedFileClientIntegrationTests.cs @@ -7,7 +7,6 @@ using System.IO; using System.Text; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable MEAI001 @@ -24,7 +23,7 @@ public void Dispose() _client?.Dispose(); } - [ConditionalFact] + [Fact] public async Task Upload_Download_Delete_Roundtrip() { SkipIfNotEnabled(); @@ -81,7 +80,7 @@ public async Task Upload_Download_Delete_Roundtrip() } } - [ConditionalFact] + [Fact] public async Task Upload_ListFiles_VerifyPresent() { SkipIfNotEnabled(); @@ -112,7 +111,7 @@ public async Task Upload_ListFiles_VerifyPresent() } } - [ConditionalFact] + [Fact] public async Task GetFileInfo_ReturnsMetadata() { SkipIfNotEnabled(); @@ -147,7 +146,7 @@ public async Task GetFileInfo_ReturnsMetadata() } } - [ConditionalFact] + [Fact] public async Task Delete_NonExistent_ReturnsFalse() { SkipIfNotEnabled(); @@ -156,7 +155,7 @@ public async Task Delete_NonExistent_ReturnsFalse() Assert.False(deleted); } - [ConditionalFact] + [Fact] public async Task GetFileInfo_NonExistent_ReturnsNull() { SkipIfNotEnabled(); @@ -165,7 +164,7 @@ public async Task GetFileInfo_NonExistent_ReturnsNull() Assert.Null(fileInfo); } - [ConditionalFact] + [Fact] public async Task Upload_DataContent_Extension() { SkipIfNotEnabled(); @@ -193,7 +192,7 @@ public async Task Upload_DataContent_Extension() } } - [ConditionalFact] + [Fact] public async Task Download_AsDataContent_Extension() { SkipIfNotEnabled(); @@ -222,7 +221,7 @@ public async Task Download_AsDataContent_Extension() } } - [ConditionalFact] + [Fact] public async Task Upload_DownloadTo_Extension() { SkipIfNotEnabled(); @@ -262,7 +261,7 @@ public async Task Upload_DownloadTo_Extension() } } - [ConditionalFact] + [Fact] public async Task Container_Upload_Download_Delete_Roundtrip() { SkipIfNotEnabled(); @@ -332,7 +331,7 @@ public async Task Container_Upload_Download_Delete_Roundtrip() Assert.True(deleted); } - [ConditionalFact] + [Fact] public async Task CodeInterpreter_ProducesDownloadableOutputs() { SkipIfNotEnabled(); @@ -382,7 +381,7 @@ public async Task CodeInterpreter_ProducesDownloadableOutputs() Assert.True(ms.Length > 0); } - [ConditionalFact] + [Fact] public async Task CodeInterpreter_Upload_ProcessedByCodeInterpreter() { SkipIfNotEnabled(); @@ -458,9 +457,6 @@ private void SkipIfNotEnabled() { string? skipIntegration = TestRunnerConfiguration.Instance["SkipIntegrationTests"]; - if (skipIntegration is not null || _client is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(skipIntegration is null && _client is not null, "Client is not enabled."); } } diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs index 28a485dfae7..24e4f580dfd 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIResponseClientIntegrationTests.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; -using Microsoft.TestUtilities; using OpenAI.Responses; using Xunit; @@ -31,7 +30,7 @@ public class OpenAIResponseClientIntegrationTests : ChatClientIntegrationTests // Test structure doesn't make sense with Responses. public override Task Caching_AfterFunctionInvocation_FunctionOutputUnchangedAsync() => Task.CompletedTask; - [ConditionalFact] + [Fact] public async Task UseCodeInterpreter_ProducesCodeExecutionResults() { SkipIfNotEnabled(); @@ -75,7 +74,7 @@ public async Task UseCodeInterpreter_ProducesCodeExecutionResults() } } - [ConditionalFact] + [Fact] public async Task UseWebSearch_AnnotationsReflectResults() { SkipIfNotEnabled(); @@ -134,17 +133,14 @@ public async Task UseWebSearch_AnnotationsReflectResults() }); } - [ConditionalTheory] + [Theory] [InlineData(false, "gpt-image-1-mini")] [InlineData(true, "gpt-image-2")] public async Task UseImageGeneration_ProducesImageContent(bool streaming, string imageModel) { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Image generation tool requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Image generation tool requires gpt-5.4 or later."); var chatOptions = new ChatOptions { @@ -187,7 +183,7 @@ public async Task UseImageGeneration_ProducesImageContent(bool streaming, string File.WriteAllBytes(tempPath, imageContent.Data.ToArray()); } - [ConditionalFact] + [Fact] public async Task RemoteMCP_ListTools() { SkipIfNotEnabled(); @@ -204,7 +200,7 @@ public async Task RemoteMCP_ListTools() Assert.Contains("ask_question", response.Text); } - [ConditionalFact] + [Fact] public async Task RemoteMCP_CallTool_ApprovalNeverRequired() { SkipIfNotEnabled(); @@ -242,7 +238,7 @@ await client.GetStreamingResponseAsync(Prompt, chatOptions).ToChatResponseAsync( } } - [ConditionalFact] + [Fact] public async Task RemoteMCP_CallTool_ApprovalRequired() { SkipIfNotEnabled(); @@ -311,15 +307,12 @@ await client.GetStreamingResponseAsync(input, chatOptions).ToChatResponseAsync() } } - [ConditionalFact] + [Fact] public async Task RemoteMCP_DeferLoadingTools() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); var mcpTool = new HostedMcpServerTool("deepwiki", new Uri("https://mcp.deepwiki.com/mcp")) { @@ -355,7 +348,7 @@ public async Task RemoteMCP_DeferLoadingTools() Assert.Contains(rawJsons, json => json.Contains("\"type\":\"tool_search_output\"") || json.Contains("\"type\": \"tool_search_output\"")); } - [ConditionalFact] + [Fact] public async Task GetResponseAsync_BackgroundResponses() { SkipIfNotEnabled(); @@ -383,7 +376,7 @@ public async Task GetResponseAsync_BackgroundResponses() Assert.Contains("whale", response.Text, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task GetResponseAsync_BackgroundResponses_WithFunction() { SkipIfNotEnabled(); @@ -418,7 +411,7 @@ public async Task GetResponseAsync_BackgroundResponses_WithFunction() Assert.Equal(1, callCount); } - [ConditionalFact] + [Fact] public async Task GetStreamingResponseAsync_BackgroundResponses() { SkipIfNotEnabled(); @@ -439,7 +432,7 @@ public async Task GetStreamingResponseAsync_BackgroundResponses() Assert.Contains("Paris", responseText, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task GetStreamingResponseAsync_BackgroundResponses_StreamResumption() { SkipIfNotEnabled(); @@ -477,7 +470,7 @@ public async Task GetStreamingResponseAsync_BackgroundResponses_StreamResumption Assert.Contains("Paris", responseText, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task GetStreamingResponseAsync_BackgroundResponses_WithFunction() { SkipIfNotEnabled(); @@ -503,16 +496,17 @@ public async Task GetStreamingResponseAsync_BackgroundResponses_WithFunction() Assert.Equal(1, callCount); } - [ConditionalFact] + [Fact] public async Task RemoteMCP_Connector() { SkipIfNotEnabled(); if (TestRunnerConfiguration.Instance["RemoteMCP:ConnectorAccessToken"] is not string { Length: > 0 } accessToken) { - throw new SkipTestException( + Assert.Skip( "To run this test, set a value for RemoteMCP:ConnectorAccessToken. " + "You can obtain one by following https://platform.openai.com/docs/guides/tools-connectors-mcp?quickstart-panels=connector#authorizing-a-connector."); + return; // Unreachable, but needed for definite assignment of 'accessToken'. } await RunAsync(false, false); @@ -563,7 +557,7 @@ await client.GetStreamingResponseAsync(input, chatOptions).ToChatResponseAsync() } } - [ConditionalFact] + [Fact] public async Task ToolCallResult_TextContent() { SkipIfNotEnabled(); @@ -583,7 +577,7 @@ public async Task ToolCallResult_TextContent() Assert.Contains("42", response.Text); } - [ConditionalFact] + [Fact] public async Task ToolCallResult_MultipleAIContents() { SkipIfNotEnabled(); @@ -611,7 +605,7 @@ public async Task ToolCallResult_MultipleAIContents() Assert.Contains("72", response.Text); } - [ConditionalFact] + [Fact] public async Task ToolCallResult_ImageDataContent() { SkipIfNotEnabled(); @@ -636,7 +630,7 @@ public async Task ToolCallResult_ImageDataContent() $"Expected response to mention logo or colors, but got: {response.Text}"); } - [ConditionalFact] + [Fact] public async Task ToolCallResult_PdfDataContent() { SkipIfNotEnabled(); @@ -656,7 +650,7 @@ public async Task ToolCallResult_PdfDataContent() Assert.Contains("Hello World", response.Text, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task ToolCallResult_MixedContentWithImage() { SkipIfNotEnabled(); @@ -688,7 +682,7 @@ public async Task ToolCallResult_MixedContentWithImage() $"Expected response to mention analysis or image content, but got: {response.Text}"); } - [ConditionalFact] + [Fact] public async Task ReasoningContent_NonStreaming_RoundtripsEncryptedContent() { SkipIfNotEnabled(); @@ -768,7 +762,7 @@ public async Task ReasoningContent_NonStreaming_RoundtripsEncryptedContent() Assert.Contains("encrypted", ex.Message, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task ReasoningContent_Streaming_RoundtripsEncryptedContent() { // This test requires a reasoning model with encrypted content support. @@ -854,15 +848,12 @@ public async Task ReasoningContent_Streaming_RoundtripsEncryptedContent() Assert.Contains("encrypted", ex.Message, StringComparison.OrdinalIgnoreCase); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_WithDeferredFunctions() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); AIFunction getWeather = AIFunctionFactory.Create(() => "Sunny, 72°F", "GetWeather", "Gets the current weather."); AIFunction getTime = AIFunctionFactory.Create(() => "3:00 PM", "GetTime", "Gets the current time."); @@ -893,15 +884,12 @@ public async Task UseToolSearch_WithDeferredFunctions() Assert.Contains(rawJsons, json => json.Contains("\"type\":\"tool_search_output\"") || json.Contains("\"type\": \"tool_search_output\"")); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_OnlyToolSearchNoFunctions_Throws() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); // HostedToolSearchTool with no deferred tools — the API rejects this with 400 // because tool_search requires at least one tool with defer_loading. @@ -914,15 +902,12 @@ await Assert.ThrowsAsync(() => })); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_WithNonDeferredFunctionsOnly_Throws() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); // HostedToolSearchTool with DeferredTools explicitly set to empty — no tools are deferred. // The API rejects this with 400 because tool_search requires at least one deferred tool. @@ -941,15 +926,12 @@ await Assert.ThrowsAsync(() => })); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_DeferLoadingOnNonDeferrableTool_Throws() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); // Force defer_loading on a code_interpreter tool via Patch — the API should reject this. var codeTool = new HostedCodeInterpreterTool(); @@ -970,15 +952,12 @@ await Assert.ThrowsAsync(() => })); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_NamespaceWithDescription_RoundTrips() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); AIFunction getWeather = AIFunctionFactory.Create(() => "Sunny, 72°F", "GetWeather", "Gets the current weather."); AIFunction getTime = AIFunctionFactory.Create(() => "3:00 PM", "GetTime", "Gets the current time."); @@ -1015,15 +994,12 @@ public async Task UseToolSearch_NamespaceWithDescription_RoundTrips() Assert.Contains(rawJsons, json => json.Contains("\"type\":\"tool_search_output\"") || json.Contains("\"type\": \"tool_search_output\"")); } - [ConditionalFact] + [Fact] public async Task UseToolSearch_TwoNamespacesWithDescriptions_RoundTrips() { SkipIfNotEnabled(); - if (TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is not true) - { - throw new SkipTestException("Tool search requires gpt-5.4 or later."); - } + Assert.SkipUnless(TestRunnerConfiguration.Instance["OpenAI:ChatModel"]?.StartsWith("gpt-5.4", StringComparison.OrdinalIgnoreCase) is true, "Tool search requires gpt-5.4 or later."); AIFunction getWeather = AIFunctionFactory.Create(() => "Sunny, 72°F", "GetWeather", "Gets the current weather."); AIFunction getTime = AIFunctionFactory.Create(() => "3:00 PM", "GetTime", "Gets the current time."); diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAISpeechToTextClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAISpeechToTextClientTests.cs index 0605a3ed655..4b348f51f65 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAISpeechToTextClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAISpeechToTextClientTests.cs @@ -352,4 +352,153 @@ private static ISpeechToTextClient CreateSpeechToTextClient(HttpClient httpClien new OpenAIClient(new ApiKeyCredential("apikey"), new OpenAIClientOptions { Transport = new HttpClientPipelineTransport(httpClient) }) .GetAudioClient(modelId) .AsISpeechToTextClient(); + + public static TheoryData AudioFormatDetectionData => new() + { + // WAV: RIFF____WAVE + { "RIFF\x00\x00\x00\x00WAVE"u8.ToArray(), "audio.wav" }, + + // MP3: ID3v2 tag + { new byte[] { (byte)'I', (byte)'D', (byte)'3', 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "audio.mp3" }, + + // MP3: MPEG sync word (0xFF 0xFB) + { new byte[] { 0xFF, 0xFB, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "audio.mp3" }, + + // WebM/Matroska: EBML header + { new byte[] { 0x1A, 0x45, 0xDF, 0xA3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, "audio.webm" }, + + // M4A/MP4: ISO BMFF ftyp box + { new byte[] { 0x00, 0x00, 0x00, 0x20, (byte)'f', (byte)'t', (byte)'y', (byte)'p', (byte)'M', (byte)'4', (byte)'A', (byte)' ' }, "audio.m4a" }, + + // Unknown bytes: defaults to mp3 + { new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C }, "audio.mp3" }, + }; + + [Theory] + [MemberData(nameof(AudioFormatDetectionData))] + public async Task GetTextAsync_DetectsAudioFormatFromMagicBytes(byte[] header, string expectedFilename) + { + const string Input = """ + { + "model": "gpt-4o-transcribe" + } + """; + + const string Output = """ + { + "text":"Hello." + } + """; + + using var audioSpeechStream = new MemoryStream(header); + + using VerbatimMultiPartHttpHandler handler = new(Input, Output) + { + ExpectedAudioFilename = expectedFilename, + }; + using HttpClient httpClient = new(handler); + using ISpeechToTextClient client = CreateSpeechToTextClient(httpClient, "gpt-4o-transcribe"); + + var response = await client.GetTextAsync(audioSpeechStream); + Assert.NotNull(response); + } + + [Theory] + [MemberData(nameof(AudioFormatDetectionData))] + public async Task GetStreamingTextAsync_DetectsAudioFormatFromMagicBytes(byte[] header, string expectedFilename) + { + const string Input = """ + { + "model": "gpt-4o-transcribe", + "stream":true + } + """; + + const string Output = """ + { + "text":"Hello." + } + """; + + using var audioSpeechStream = new MemoryStream(header); + + using VerbatimMultiPartHttpHandler handler = new(Input, Output) + { + ExpectedRequestUriContains = "audio/transcriptions", + ExpectedAudioFilename = expectedFilename, + }; + using HttpClient httpClient = new(handler); + using ISpeechToTextClient client = CreateSpeechToTextClient(httpClient, "gpt-4o-transcribe"); + + await foreach (var update in client.GetStreamingTextAsync(audioSpeechStream)) + { + Assert.NotNull(update); + } + } + + [Fact] + public async Task GetTextAsync_StreamPositionNotAtZero_SkipsDetectionAndDefaultsToMp3() + { + const string Input = """ + { + "model": "gpt-4o-transcribe" + } + """; + + const string Output = """ + { + "text":"Hello." + } + """; + + // WAV magic bytes, but position advanced past them — detection should be skipped. + byte[] wavHeader = "RIFF\x00\x00\x00\x00WAVE"u8.ToArray(); + using var audioSpeechStream = new MemoryStream(wavHeader); + audioSpeechStream.Position = 4; + + using VerbatimMultiPartHttpHandler handler = new(Input, Output) + { + ExpectedAudioFilename = "audio.mp3", + }; + using HttpClient httpClient = new(handler); + using ISpeechToTextClient client = CreateSpeechToTextClient(httpClient, "gpt-4o-transcribe"); + + var response = await client.GetTextAsync(audioSpeechStream); + Assert.NotNull(response); + } + + [Fact] + public async Task GetStreamingTextAsync_StreamPositionNotAtZero_SkipsDetectionAndDefaultsToMp3() + { + const string Input = """ + { + "model": "gpt-4o-transcribe", + "stream":true + } + """; + + const string Output = """ + { + "text":"Hello." + } + """; + + // WAV magic bytes, but position advanced past them — detection should be skipped. + byte[] wavHeader = "RIFF\x00\x00\x00\x00WAVE"u8.ToArray(); + using var audioSpeechStream = new MemoryStream(wavHeader); + audioSpeechStream.Position = 4; + + using VerbatimMultiPartHttpHandler handler = new(Input, Output) + { + ExpectedRequestUriContains = "audio/transcriptions", + ExpectedAudioFilename = "audio.mp3", + }; + using HttpClient httpClient = new(handler); + using ISpeechToTextClient client = CreateSpeechToTextClient(httpClient, "gpt-4o-transcribe"); + + await foreach (var update in client.GetStreamingTextAsync(audioSpeechStream)) + { + Assert.NotNull(update); + } + } } diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAITextToSpeechClientIntegrationTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAITextToSpeechClientIntegrationTests.cs index 686fda917e1..11e927d5066 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAITextToSpeechClientIntegrationTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAITextToSpeechClientIntegrationTests.cs @@ -1,9 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; #pragma warning disable MEAI001 @@ -17,14 +16,11 @@ public class OpenAITextToSpeechClientIntegrationTests : TextToSpeechClientIntegr .GetAudioClient(TestRunnerConfiguration.Instance["OpenAI:TextToSpeechModel"] ?? "tts-1") .AsITextToSpeechClient(); - [ConditionalFact] + [Fact] public async Task GetStreamingAudioAsync_StreamingModel_ReturnsMultipleUpdatesWithUsage() { var openAIClient = IntegrationTestHelpers.GetOpenAIClient(); - if (openAIClient is null) - { - throw new SkipTestException("Client is not enabled."); - } + Assert.SkipUnless(openAIClient is not null, "Client is not enabled."); using ITextToSpeechClient client = openAIClient .GetAudioClient(TestRunnerConfiguration.Instance["OpenAI:TextToSpeechStreamingModel"] ?? "gpt-4o-mini-tts") diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs index 1fcf22fa292..bcdc55d6b7c 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs @@ -83,6 +83,9 @@ public async Task AllFunctionCallsReplacedWithApprovalsWhenAnyRequireApprovalAsy [ new ToolApprovalRequestContent("ficc_callId1", new FunctionCallContent("callId1", "Func1")), new ToolApprovalRequestContent("ficc_callId2", new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })) + { + RequiresConfirmation = false, + } ]) ]; @@ -121,12 +124,20 @@ public async Task AllFunctionCallsReplacedWithApprovalsWhenAnyRequestOrAdditiona new ChatMessage(ChatRole.Assistant, [new FunctionCallContent("callId1", "Func1"), new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })]), ]; + // When additionalToolsRequireApproval is true: Func1 (additional tools) requires approval and Func2 (options.Tools) does not. + // When false: Func2 (options.Tools) requires approval and Func1 (additional tools) does not. List expectedOutput = [ new ChatMessage(ChatRole.Assistant, [ - new ToolApprovalRequestContent("ficc_callId1", new FunctionCallContent("callId1", "Func1")), + new ToolApprovalRequestContent("ficc_callId1", new FunctionCallContent("callId1", "Func1")) + { + RequiresConfirmation = additionalToolsRequireApproval, + }, new ToolApprovalRequestContent("ficc_callId2", new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })) + { + RequiresConfirmation = !additionalToolsRequireApproval, + } ]) ]; @@ -135,6 +146,99 @@ public async Task AllFunctionCallsReplacedWithApprovalsWhenAnyRequestOrAdditiona await InvokeAndAssertStreamingAsync(options, input, downstreamClientOutput, expectedOutput, additionalTools: additionalTools); } + private sealed class PassThroughDelegatingAIFunction(AIFunction inner) : DelegatingAIFunction(inner); + + [Fact] + public async Task RequiresConfirmation_IsTrueForApprovalRequiredFunctionNestedInDelegatingWrapperAsync() + { + // Wrap the ApprovalRequiredAIFunction in another DelegatingAIFunction (e.g. a telemetry decorator). + // FICC must still classify the call as approval-required (RequiresConfirmation = true, the default) + // by walking the delegation chain via GetService(). + AITool[] tools = + [ + new PassThroughDelegatingAIFunction( + new ApprovalRequiredAIFunction( + AIFunctionFactory.Create(() => "Result 1", "Func1"))), + AIFunctionFactory.Create((int i) => $"Result 2: {i}", "Func2"), + ]; + + var options = new ChatOptions { Tools = tools }; + + List input = + [ + new ChatMessage(ChatRole.User, "hello"), + ]; + + List downstreamClientOutput = + [ + new ChatMessage(ChatRole.Assistant, [ + new FunctionCallContent("callId1", "Func1"), + new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } }) + ]), + ]; + + List expectedOutput = + [ + new ChatMessage(ChatRole.Assistant, + [ + new ToolApprovalRequestContent("ficc_callId1", new FunctionCallContent("callId1", "Func1")), + new ToolApprovalRequestContent("ficc_callId2", new FunctionCallContent("callId2", "Func2", arguments: new Dictionary { { "i", 42 } })) + { + RequiresConfirmation = false, + } + ]) + ]; + + await InvokeAndAssertAsync(options, input, downstreamClientOutput, expectedOutput); + + await InvokeAndAssertStreamingAsync(options, input, downstreamClientOutput, expectedOutput); + } + + [Fact] + public async Task RequiresConfirmation_IsFalseForFunctionCallWithNoMatchingToolWhenPeerRequiresApprovalAsync() + { + // The downstream client emits an FCC referencing a tool name that is not in the tools list. + // Because a peer call (Func1) requires approval, FICC still wraps the unknown call. + // Since no matching tool is found (and therefore no ApprovalRequiredAIFunction is detected), + // the resulting approval request must carry RequiresConfirmation = false. + var options = new ChatOptions + { + Tools = + [ + new ApprovalRequiredAIFunction(AIFunctionFactory.Create(() => "Result 1", "Func1")), + ] + }; + + List input = + [ + new ChatMessage(ChatRole.User, "hello"), + ]; + + List downstreamClientOutput = + [ + new ChatMessage(ChatRole.Assistant, [ + new FunctionCallContent("callId1", "Func1"), + new FunctionCallContent("callId2", "Unknown"), + ]), + ]; + + List expectedOutput = + [ + new ChatMessage(ChatRole.Assistant, + [ + new ToolApprovalRequestContent("ficc_callId1", new FunctionCallContent("callId1", "Func1")), + new ToolApprovalRequestContent("ficc_callId2", new FunctionCallContent("callId2", "Unknown")) + { + RequiresConfirmation = false, + } + ]) + ]; + + await InvokeAndAssertAsync(options, input, downstreamClientOutput, expectedOutput); + + await InvokeAndAssertStreamingAsync(options, input, downstreamClientOutput, expectedOutput); + } + [Fact] public async Task ApprovedApprovalResponsesAreExecutedAsync() { @@ -1735,7 +1839,10 @@ private static List CloneInput(List input) => InformationalOnly = fcc.InformationalOnly }, ToolApprovalRequestContent tarc => - new ToolApprovalRequestContent(tarc.RequestId, (ToolCallContent)CloneFcc(tarc.ToolCall)), + new ToolApprovalRequestContent(tarc.RequestId, (ToolCallContent)CloneFcc(tarc.ToolCall)) + { + RequiresConfirmation = tarc.RequiresConfirmation, + }, ToolApprovalResponseContent tarc => new ToolApprovalResponseContent(tarc.RequestId, tarc.Approved, (ToolCallContent)CloneFcc(tarc.ToolCall)) { diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/ImageGeneratingChatClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/ImageGeneratingChatClientTests.cs index 0571b06d9fc..f8bc3ee1974 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/ImageGeneratingChatClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/ImageGeneratingChatClientTests.cs @@ -383,4 +383,152 @@ async IAsyncEnumerable GetUpdatesAsync() var imageToolCallContent = Assert.IsType(update.Contents[0]); Assert.Equal(callId, imageToolCallContent.CallId); } + + [Theory] + [InlineData("at-start")] + [InlineData("in-middle")] + [InlineData("at-end")] + public async Task GetResponseAsync_FunctionCallContent_SurroundingContentPreservedInOrder(string position) + { + // Regression test for: image generation content duplicating preceding content and dropping following content. + // The image-generation FunctionCallContent should be replaced with ImageGenerationToolCallContent, + // while all other content items retain their original order and cardinality. + var imageCallId = "image-call-id"; + var otherCallId = "other-call-id"; + + using var innerClient = new TestChatClient + { + GetResponseAsyncCallback = (messages, options, cancellationToken) => + { + IList contents = position switch + { + "at-start" => [new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" }), + new FunctionResultContent(otherCallId, "other-result")], + "at-end" => [new FunctionResultContent(otherCallId, "other-result"), + new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" })], + _ => [new FunctionResultContent(otherCallId, "before-result"), + new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" }), + new UsageContent(new UsageDetails { InputTokenCount = 5 })], + }; + return Task.FromResult(new ChatResponse(new ChatMessage(ChatRole.Assistant, contents))); + }, + }; + + using var imageGenerator = new TestImageGenerator(); + using var client = new ImageGeneratingChatClient(innerClient, imageGenerator); + + var chatOptions = new ChatOptions + { + Tools = [new HostedImageGenerationTool()] + }; + + // Act + var response = await client.GetResponseAsync([new(ChatRole.User, "test")], chatOptions); + + // Assert + Assert.NotNull(response); + Assert.Single(response.Messages); + var contents = response.Messages[0].Contents; + + if (position == "at-start") + { + Assert.Equal(2, contents.Count); + Assert.IsType(contents[0]); + var otherResult = Assert.IsType(contents[1]); + Assert.Equal(otherCallId, otherResult.CallId); + } + else if (position == "at-end") + { + Assert.Equal(2, contents.Count); + var otherResult = Assert.IsType(contents[0]); + Assert.Equal(otherCallId, otherResult.CallId); + Assert.IsType(contents[1]); + } + else + { + Assert.Equal(3, contents.Count); + var beforeResult = Assert.IsType(contents[0]); + Assert.Equal(otherCallId, beforeResult.CallId); + Assert.IsType(contents[1]); + var usageContent = Assert.IsType(contents[2]); + Assert.Equal(5, usageContent.Details.InputTokenCount); + } + } + + [Theory] + [InlineData("at-start")] + [InlineData("in-middle")] + [InlineData("at-end")] + public async Task GetStreamingResponseAsync_FunctionCallContent_SurroundingContentPreservedInOrder(string position) + { + // Regression test for: image generation content duplicating preceding content and dropping following content. + // The image-generation FunctionCallContent should be replaced with ImageGenerationToolCallContent, + // while all other content items retain their original order and cardinality. + var imageCallId = "image-call-id"; + var otherCallId = "other-call-id"; + + using var innerClient = new TestChatClient + { + GetStreamingResponseAsyncCallback = (messages, options, cancellationToken) => GetUpdatesAsync() + }; + + async IAsyncEnumerable GetUpdatesAsync() + { + await Task.Yield(); + IList contents = position switch + { + "at-start" => [new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" }), + new FunctionResultContent(otherCallId, "other-result")], + "at-end" => [new FunctionResultContent(otherCallId, "other-result"), + new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" })], + _ => [new FunctionResultContent(otherCallId, "before-result"), + new FunctionCallContent(imageCallId, "GenerateImage", new Dictionary { ["prompt"] = "a cat" }), + new UsageContent(new UsageDetails { InputTokenCount = 5 })], + }; + yield return new ChatResponseUpdate(ChatRole.Assistant, contents); + } + + using var imageGenerator = new TestImageGenerator(); + using var client = new ImageGeneratingChatClient(innerClient, imageGenerator); + + var chatOptions = new ChatOptions + { + Tools = [new HostedImageGenerationTool()] + }; + + // Act + var updates = new List(); + await foreach (var update in client.GetStreamingResponseAsync([new(ChatRole.User, "test")], chatOptions)) + { + updates.Add(update); + } + + // Assert + Assert.Single(updates); + var contents = updates[0].Contents; + + if (position == "at-start") + { + Assert.Equal(2, contents.Count); + Assert.IsType(contents[0]); + var otherResult = Assert.IsType(contents[1]); + Assert.Equal(otherCallId, otherResult.CallId); + } + else if (position == "at-end") + { + Assert.Equal(2, contents.Count); + var otherResult = Assert.IsType(contents[0]); + Assert.Equal(otherCallId, otherResult.CallId); + Assert.IsType(contents[1]); + } + else + { + Assert.Equal(3, contents.Count); + var beforeResult = Assert.IsType(contents[0]); + Assert.Equal(otherCallId, beforeResult.CallId); + Assert.IsType(contents[1]); + var usageContent = Assert.IsType(contents[2]); + Assert.Equal(5, usageContent.Details.InputTokenCount); + } + } } diff --git a/test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs b/test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs index 1bd803aded3..cbe6e2812a5 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Tests/Functions/AIFunctionFactoryTest.cs @@ -10,6 +10,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -18,6 +19,7 @@ #pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable S103 // Lines should not be too long #pragma warning disable S107 // Methods should not have too many parameters +#pragma warning disable S1144 // Unused private types or members should be removed (accessed via reflection) #pragma warning disable S2760 // Sequential tests should not check the same condition #pragma warning disable S3358 // Ternary operators should not be nested #pragma warning disable S5034 // "ValueTask" should be consumed correctly @@ -115,6 +117,7 @@ public async Task Parameters_MissingRequiredParametersFail_Async() AIFunctionFactory.Create((string? theParam) => theParam + " " + theParam), AIFunctionFactory.Create((int theParam) => theParam * 2), AIFunctionFactory.Create((int? theParam) => theParam * 2), + AIFunctionFactory.Create(([AIParameterName("theParam")] string otherName) => otherName), ]; foreach (AIFunction f in funcs) @@ -315,6 +318,172 @@ public void Metadata_DisplayNameAttribute() Assert.Contains("Metadata_DisplayNameAttribute", func.Name); // Will contain the lambda method name } + [Fact] + public void Metadata_AIFunctionNameAttribute() + { + Func funcWithAttribute = [AIFunctionName("get_user")] () => "test"; + AIFunction func = AIFunctionFactory.Create(funcWithAttribute); + Assert.Equal("get_user", func.Name); + + Func funcWithBoth = [AIFunctionName("my_function")][DisplayName("display_name")] () => "test"; + func = AIFunctionFactory.Create(funcWithBoth); + Assert.Equal("my_function", func.Name); + + func = AIFunctionFactory.Create(funcWithAttribute, name: "explicit_name"); + Assert.Equal("explicit_name", func.Name); + + func = AIFunctionFactory.Create(funcWithAttribute, new AIFunctionFactoryOptions { Name = "options_name" }); + Assert.Equal("options_name", func.Name); + } + + [Fact] + public void Metadata_AIFunctionAndParameterNameAttributes_PreservedByAsDeclarationOnly() + { + AIFunction func = AIFunctionFactory.Create([AIFunctionName("my_tool")] ([AIParameterName("my_param")] string myParam) => myParam); + + AIFunctionDeclaration declaration = func.AsDeclarationOnly(); + + Assert.Equal("my_tool", declaration.Name); + Assert.Equal(func.JsonSchema.ToString(), declaration.JsonSchema.ToString()); + Assert.Contains("my_param", declaration.JsonSchema.ToString()); + Assert.IsNotAssignableFrom(declaration); + } + + [Fact] + public async Task Parameters_MappedByAIParameterNameAttribute_Async() + { + AIFunction func = AIFunctionFactory.Create(([AIParameterName("$select")] string select, int top) => select + top); + + AssertExtensions.EqualFunctionCallResults("Name2", await func.InvokeAsync(new() { ["$select"] = "Name", ["top"] = 2 })); + } + + [Fact] + public void Parameters_AIParameterNameAttribute_OverridesSchemaPropertyName() + { + AIFunction func = AIFunctionFactory.Create( + ([AIParameterName("my_param")] string myParam, int top) => myParam + top); + + JsonElement expectedSchema = JsonDocument.Parse(""" + { + "type": "object", + "properties": { + "my_param": { "type": "string" }, + "top": { "type": "integer" } + }, + "required": ["my_param", "top"] + } + """).RootElement; + + AssertExtensions.EqualJsonValues(expectedSchema, func.JsonSchema); + } + + [Fact] + public async Task Parameters_AIParameterNameAttribute_StrictUnmappedMemberHandling_Async() + { + JsonSerializerOptions strictOptions = new(AIJsonUtilities.DefaultOptions) + { + UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow, + }; + + AIFunction func = AIFunctionFactory.Create( + ([AIParameterName("my_param")] string myParam) => myParam, + new AIFunctionFactoryOptions { SerializerOptions = strictOptions }); + + // The overridden name is "expected", so it passes strict validation. + AssertExtensions.EqualFunctionCallResults("Name", await func.InvokeAsync(new() { ["my_param"] = "Name" })); + + // The underlying C# name is now an unexpected argument. + ArgumentException ex = await Assert.ThrowsAsync("arguments", async () => + await func.InvokeAsync(new() { ["myParam"] = "Name" })); + Assert.Contains("myParam", ex.Message); + } + + [Fact] + public async Task Parameters_AIParameterNameAttribute_InheritedByOverride_Async() + { + MethodInfo overrideMethod = typeof(MyDerivedType).GetMethod(nameof(MyDerivedType.Method))!; + AIFunction func = AIFunctionFactory.Create(overrideMethod, new MyDerivedType()); + + Assert.Contains("my_param", func.JsonSchema.ToString()); + Assert.DoesNotContain("\"myParam\"", func.JsonSchema.ToString()); + + AssertExtensions.EqualFunctionCallResults("param='Name'", await func.InvokeAsync(new() { ["my_param"] = "Name" })); + } + + [Fact] + public void Parameters_AIParameterNameAttribute_EscapesJsonPointerRef() + { + JsonSerializerOptions options = new(AIJsonUtilities.DefaultOptions) { TypeInfoResolver = new DefaultJsonTypeInfoResolver() }; + + AIFunction func = AIFunctionFactory.Create( + ([AIParameterName("a/b~c")] AIParameterNameAttributeRecursiveNode node) => node.ToString(), + new AIFunctionFactoryOptions { SerializerOptions = options }); + + string schema = func.JsonSchema.ToString(); + + Assert.Contains("#/properties/a~1b~0c", schema); + Assert.DoesNotContain("#/properties/a/b~c", schema); + } + + [Fact] + public void Parameters_AIParameterNameAttribute_DuplicateNames_Throw() + { + ArgumentException ex = Assert.Throws(() => AIFunctionFactory.Create( + ([AIParameterName("dup")] string first, [AIParameterName("dup")] string second) => first + second)); + Assert.Contains("dup", ex.Message); + Assert.Equal("method", ex.ParamName); + + ArgumentException ex2 = Assert.Throws(() => AIFunctionFactory.Create( + ([AIParameterName("filter")] string select, string filter) => select + filter)); + Assert.Contains("filter", ex2.Message); + Assert.Equal("method", ex2.ParamName); + } + + [Fact] + public void Parameters_AIParameterNameAttribute_DuplicateNames_ExcludedFromSchema() + { + // Validates that collision detection occurs in ExpectedArgumentNames collection + // even when one of the colliding parameters is excluded from schema generation. + // This addresses the concern that collisions might go undetected when + // ExcludeFromSchema = true for one of the parameters. + + var options = new AIFunctionFactoryOptions + { + ConfigureParameterBinding = p => p.Name == "second" + ? new AIFunctionFactoryOptions.ParameterBindingOptions { ExcludeFromSchema = true } + : default + }; + + ArgumentException ex = Assert.Throws(() => AIFunctionFactory.Create( + ([AIParameterName("dup")] string first, [AIParameterName("dup")] string second) => first + second, + options)); + Assert.Contains("dup", ex.Message); + Assert.Contains("AIParameterNameAttribute", ex.Message); + Assert.Equal("method", ex.ParamName); + } + + [Fact] + public void AIFunctionFactory_InheritedDescriptionAttributes_OnOverride() + { + MethodInfo overrideMethod = typeof(DerivedDescribed).GetMethod(nameof(DerivedDescribed.Compute))!; + AIFunction f = AIFunctionFactory.Create(overrideMethod, new DerivedDescribed()); + + Assert.Equal("The compute method", f.Description); + + JsonElement valueParam = f.JsonSchema.GetProperty("properties").GetProperty("value"); + Assert.Equal("The input value", valueParam.GetProperty("description").GetString()); + + Assert.NotNull(f.ReturnJsonSchema); + Assert.Equal("integer", f.ReturnJsonSchema!.Value.GetProperty("type").GetString()); +#if NET + // On modern .NET the return-parameter inheritance walk is fixed, so the inherited description is read. + Assert.Equal("The computed result", f.ReturnJsonSchema!.Value.GetProperty("description").GetString()); +#else + // On .NET Framework the inherited return-parameter description cannot be read and is silently dropped. + Assert.False(f.ReturnJsonSchema!.Value.TryGetProperty("description", out _)); +#endif + } + [Fact] public void AIFunctionFactoryCreateOptions_ValuesPropagateToAIFunction() { @@ -1592,4 +1761,31 @@ public async Task Parameters_UnmappedMemberHandlingDisallow_CustomBindParameter_ [JsonSerializable(typeof(int?))] [JsonSerializable(typeof(DateTime?))] private partial class JsonContext : JsonSerializerContext; + + private abstract class MyBaseType + { + public abstract string Method([AIParameterName("my_param")] string myParam); + } + + private sealed class MyDerivedType : MyBaseType + { + public override string Method(string myParam) => $"param='{myParam}'"; + } + + private sealed class AIParameterNameAttributeRecursiveNode + { + public AIParameterNameAttributeRecursiveNode? Next { get; set; } + } + + private abstract class BaseDescribed + { + [Description("The compute method")] + [return: Description("The computed result")] + public abstract int Compute([Description("The input value")] int value); + } + + private sealed class DerivedDescribed : BaseDescribed + { + public override int Compute(int value) => value; + } } diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/DistributedCacheTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/DistributedCacheTests.cs index 0e86c742c5a..5c6beb925a2 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/DistributedCacheTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/DistributedCacheTests.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Caching.Hybrid.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Internal; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/ExpirationTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/ExpirationTests.cs index 562ba8ae98f..9a528e854b5 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/ExpirationTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/ExpirationTests.cs @@ -1,11 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Internal; -using Xunit.Abstractions; +using Xunit; using static Microsoft.Extensions.Caching.Hybrid.Tests.DistributedCacheTests; using static Microsoft.Extensions.Caching.Hybrid.Tests.L2Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/HybridCacheEventSourceTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/HybridCacheEventSourceTests.cs index 8e23143475f..ad27a0054e0 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/HybridCacheEventSourceTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/HybridCacheEventSourceTests.cs @@ -1,9 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.Tracing; using Microsoft.Extensions.Caching.Hybrid.Internal; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; @@ -11,7 +11,7 @@ public class HybridCacheEventSourceTests(ITestOutputHelper log, TestEventListene { // see notes in TestEventListener for context on fixture usage - [SkippableFact] + [Fact] public void MatchesNameAndGuid() { // Assert @@ -19,7 +19,7 @@ public void MatchesNameAndGuid() Assert.Equal(Guid.Parse("b3aca39e-5dc9-5e21-f669-b72225b66cfc"), listener.Source.Guid); // from name } - [SkippableFact] + [Fact] public async Task LocalCacheHit() { AssertEnabled(); @@ -32,7 +32,7 @@ public async Task LocalCacheHit() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task LocalCacheMiss() { AssertEnabled(); @@ -45,7 +45,7 @@ public async Task LocalCacheMiss() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheGet() { AssertEnabled(); @@ -58,7 +58,7 @@ public async Task DistributedCacheGet() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheHit() { AssertEnabled(); @@ -72,7 +72,7 @@ public async Task DistributedCacheHit() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheMiss() { AssertEnabled(); @@ -86,7 +86,7 @@ public async Task DistributedCacheMiss() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheFailed() { AssertEnabled(); @@ -99,7 +99,7 @@ public async Task DistributedCacheFailed() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheCanceled() { AssertEnabled(); @@ -112,7 +112,7 @@ public async Task DistributedCacheCanceled() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task UnderlyingDataQueryStart() { AssertEnabled(); @@ -126,7 +126,7 @@ public async Task UnderlyingDataQueryStart() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task UnderlyingDataQueryComplete() { AssertEnabled(); @@ -140,7 +140,7 @@ public async Task UnderlyingDataQueryComplete() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task UnderlyingDataQueryFailed() { AssertEnabled(); @@ -154,7 +154,7 @@ public async Task UnderlyingDataQueryFailed() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task UnderlyingDataQueryCanceled() { AssertEnabled(); @@ -168,7 +168,7 @@ public async Task UnderlyingDataQueryCanceled() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task LocalCacheWrite() { AssertEnabled(); @@ -181,7 +181,7 @@ public async Task LocalCacheWrite() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task DistributedCacheWrite() { AssertEnabled(); @@ -194,7 +194,7 @@ public async Task DistributedCacheWrite() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task StampedeJoin() { AssertEnabled(); @@ -207,7 +207,7 @@ public async Task StampedeJoin() listener.AssertRemainingCountersZero(); } - [SkippableFact] + [Fact] public async Task TagInvalidated() { AssertEnabled(); @@ -225,7 +225,7 @@ private void AssertEnabled() // including this data for visibility when tests fail - ETW subsystem can be ... weird log.WriteLine($".NET {Environment.Version} on {Environment.OSVersion}, {IntPtr.Size * 8}-bit"); - Skip.IfNot(listener.Source.IsEnabled(), "Event source not enabled"); + Assert.SkipUnless(listener.Source.IsEnabled(), "Event source not enabled"); } private async Task AssertCountersAsync() @@ -240,6 +240,9 @@ private async Task AssertCountersAsync() // fundamentally working. We're not meant to be testing that // the counters system *itself* works! - Skip.If(count == 0, "No counters received"); + if (count == 0) + { + Assert.Skip("No counters received"); + } } } diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/L2Tests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/L2Tests.cs index f5be5b5277d..e54ac679ae2 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/L2Tests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/L2Tests.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LocalInvalidationTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LocalInvalidationTests.cs index 6efc4b14d45..0f1829e170c 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LocalInvalidationTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LocalInvalidationTests.cs @@ -1,11 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Hybrid.Internal; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; +using Xunit; using static Microsoft.Extensions.Caching.Hybrid.Tests.L2Tests; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LogCollector.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LogCollector.cs index 553fe1f1cd4..0ef9d975867 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LogCollector.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/LogCollector.cs @@ -1,8 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Logging; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/Microsoft.Extensions.Caching.Hybrid.Tests.csproj b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/Microsoft.Extensions.Caching.Hybrid.Tests.csproj index 3cd6a56dca5..4c692e62b24 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/Microsoft.Extensions.Caching.Hybrid.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/Microsoft.Extensions.Caching.Hybrid.Tests.csproj @@ -1,7 +1,7 @@  - $(NetCoreTargetFrameworks)$(ConditionalNet462) + $(NetCoreTargetFrameworks)$(ConditionalNet472) enable enable true @@ -20,7 +20,6 @@ - diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/PayloadTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/PayloadTests.cs index 6ee4a8a5558..169b400bf42 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/PayloadTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/PayloadTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; @@ -7,7 +7,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; +using Xunit; using static Microsoft.Extensions.Caching.Hybrid.Tests.DistributedCacheTests; using static Microsoft.Extensions.Caching.Hybrid.Tests.L2Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/RedisTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/RedisTests.cs index 86303044c48..026adafcefe 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/RedisTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/RedisTests.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Caching.StackExchangeRedis; using Microsoft.Extensions.DependencyInjection; using StackExchange.Redis; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; @@ -81,9 +81,17 @@ await cache.GetOrCreateAsync(key, _ => Assert.Equal(1, count); - await Task.Delay(500); // the L2 write continues in the background; give it a chance + // the L2 write continues in the background; poll up to 50 times (5 seconds total) until the key surfaces a TTL + TimeSpan? ttl = null; + for (var i = 0; i < 50 && ttl is null; i++) + { + ttl = await redis.GetDatabase().KeyTimeToLiveAsync(key); + if (ttl is null) + { + await Task.Delay(100); + } + } - var ttl = await redis.GetDatabase().KeyTimeToLiveAsync(key); Log.WriteLine($"ttl: {ttl}"); Assert.NotNull(ttl); } diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SizeTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SizeTests.cs index 8085a4318c0..1f8c99287b4 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SizeTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SizeTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Buffers; @@ -7,7 +7,7 @@ using Microsoft.Extensions.Caching.Hybrid.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SqlServerTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SqlServerTests.cs index e2859ec9f0b..33b123539f6 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SqlServerTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/SqlServerTests.cs @@ -3,7 +3,7 @@ using Microsoft.Data.SqlClient; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/StampedeTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/StampedeTests.cs index d9addf03aa2..f5f3a98c1ea 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/StampedeTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/StampedeTests.cs @@ -215,12 +215,15 @@ public async Task MultipleCallsShareExecution_EveryoneCancels(int callerCount) cancel.Cancel(); } - await Task.Delay(500); // cancellation happens on a worker; need to allow a moment + // allow the shared underlying task time to enter its semaphore wait + await Task.Delay(500); + for (var i = 0; i < callerCount; i++) { var result = results[i]; - // should have already cancelled, even though underlying task hasn't finished yet + // cancellation happens on a worker; wait up to 5 seconds total for the caller's task to observe its cancel + await WaitForCompletionAsync(result, 5_000); Assert.Equal(TaskStatus.Canceled, result.Status); var ex = Assert.Throws(() => result.GetAwaiter().GetResult()); Assert.Equal(cancels[i].Token, ex.CancellationToken); // each gets the correct blame @@ -296,14 +299,17 @@ public async Task MultipleCallsShareExecution_MostCancel(int callerCount, int re } } - await Task.Delay(500); // cancellation happens on a worker; need to allow a moment + // allow the shared underlying task time to enter its semaphore wait + await Task.Delay(500); + for (var i = 0; i < callerCount; i++) { if (i != remaining) { var result = results[i]; - // should have already cancelled, even though underlying task hasn't finished yet + // cancellation happens on a worker; wait up to 5 seconds total for the caller's task to observe its cancel + await WaitForCompletionAsync(result, 5_000); Assert.Equal(TaskStatus.Canceled, result.Status); var ex = Assert.Throws(() => result.GetAwaiter().GetResult()); Assert.Equal(cancels[i].Token, ex.CancellationToken); // each gets the correct blame @@ -491,4 +497,23 @@ public sealed class Immutable(Guid value) } private static string Me([CallerMemberName] string caller = "") => caller; + + private static async Task WaitForCompletionAsync( + Task task, + int timeoutMs, + [CallerArgumentExpression(nameof(task))] string? expression = null) + { + if (task.IsCompleted) + { + return; + } + +#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks + var completed = await Task.WhenAny(task, Task.Delay(timeoutMs)); +#pragma warning restore VSTHRD003 + if (completed != task) + { + throw new TimeoutException($"Task '{expression}' did not complete within {timeoutMs}ms"); + } + } } diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/TagSetTests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/TagSetTests.cs index 818dac7b45c..71e59c76fc5 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/TagSetTests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/TagSetTests.cs @@ -165,7 +165,7 @@ string Create() { const string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; var len = rand.Next(3, 8); -#if NET462 +#if NETFRAMEWORK char[] chars = new char[len]; #else Span chars = stackalloc char[len]; diff --git a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/UnreliableL2Tests.cs b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/UnreliableL2Tests.cs index bba5020f58b..d01be3d7c07 100644 --- a/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/UnreliableL2Tests.cs +++ b/test/Libraries/Microsoft.Extensions.Caching.Hybrid.Tests/UnreliableL2Tests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; @@ -7,7 +7,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.Caching.Hybrid.Tests; diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/IngestionPipelineTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/IngestionPipelineTests.cs index 2220fa25b99..7159cdc8718 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/IngestionPipelineTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/IngestionPipelineTests.cs @@ -8,9 +8,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using CommunityToolkit.VectorData.InMemory; using Microsoft.Extensions.AI; using Microsoft.ML.Tokenizers; -using Microsoft.SemanticKernel.Connectors.InMemory; using OpenTelemetry; using OpenTelemetry.Resources; using OpenTelemetry.Trace; diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Microsoft.Extensions.DataIngestion.Tests.csproj b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Microsoft.Extensions.DataIngestion.Tests.csproj index c3567512d87..47fc62913d2 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Microsoft.Extensions.DataIngestion.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Microsoft.Extensions.DataIngestion.Tests.csproj @@ -1,4 +1,4 @@ - + @@ -15,15 +15,14 @@ - - - + + @@ -31,6 +30,11 @@ + + + + + diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/DocumentReaderConformanceTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/DocumentReaderConformanceTests.cs index d4993ad2cea..3fc4f10c6f8 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/DocumentReaderConformanceTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/DocumentReaderConformanceTests.cs @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DataIngestion.Tests.Utils; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.DataIngestion.Readers.Tests; @@ -19,7 +18,7 @@ public abstract class DocumentReaderConformanceTests protected abstract IngestionDocumentReader CreateDocumentReader(bool extractImages = false); - [ConditionalFact] + [Fact] public async Task ThrowsWhenIdentifierIsNotProvided() { var reader = CreateDocumentReader(); @@ -32,7 +31,7 @@ public async Task ThrowsWhenIdentifierIsNotProvided() await Assert.ThrowsAsync("identifier", async () => await reader.ReadAsync(stream, identifier: string.Empty, mediaType: "some")); } - [ConditionalFact] + [Fact] public async Task ThrowsIfCancellationRequestedStream() { var reader = CreateDocumentReader(); @@ -43,7 +42,7 @@ public async Task ThrowsIfCancellationRequestedStream() await Assert.ThrowsAsync(async () => await reader.ReadAsync(stream, "id", "mediaType", cts.Token)); } - [ConditionalFact] + [Fact] public async Task ThrowsIfCancellationRequestedFile() { string filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName() + ".txt"); @@ -74,7 +73,7 @@ public async Task ThrowsIfCancellationRequestedFile() "https://www.bondcap.com/report/pdf/Trends_Artificial_Intelligence.pdf", // PDF file (presentation) ]; - [ConditionalTheory] + [Theory] [MemberData(nameof(Links))] public virtual async Task SupportsStreams(string source) { @@ -87,7 +86,7 @@ await response.Content.ReadAsStreamAsync(), SimpleAsserts(document, source, source); } - [ConditionalTheory] + [Theory] [MemberData(nameof(Links))] public virtual async Task SupportsFiles(string source) { @@ -105,7 +104,7 @@ public virtual async Task SupportsFiles(string source) } } - [ConditionalFact] + [Fact] public virtual Task SupportsImages() => SupportsImagesCore( new("https://winprotocoldocs-bhdugrdyduf5h2e4.b02.azurefd.net/MC-SQLR/%5bMC-SQLR%5d.pdf")); // SQL Server Resolution Protocol @@ -128,7 +127,7 @@ protected async Task SupportsImagesCore(Uri source) } } - [ConditionalFact] + [Fact] public virtual async Task SupportsTables() { string[,] expected = @@ -172,7 +171,8 @@ protected static async Task DownloadAsync(Uri uri) } catch (Exception ex) { - throw new SkipTestException($"Unable to download the test file: '{ex.Message}'"); + Assert.Skip($"Unable to download the test file: '{ex.Message}'"); + throw; // Unreachable, but needed to satisfy compiler return requirement. } } diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionAttribute.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionHelper.cs similarity index 65% rename from test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionAttribute.cs rename to test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionHelper.cs index b0169a54c1c..a2f4a432832 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionAttribute.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownConditionHelper.cs @@ -1,26 +1,20 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.ComponentModel; using System.Diagnostics; using System.Text; -using Microsoft.TestUtilities; namespace Microsoft.Extensions.DataIngestion.Readers.Tests; /// -/// This class exists because currently the local copy of can't ignore tests that throw . +/// Checks whether MarkItDown is installed and accessible. Used to conditionally skip tests. /// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] -public class MarkItDownConditionAttribute : Attribute, ITestCondition +internal static class MarkItDownConditionHelper { internal static readonly Lazy IsInstalled = new(CanInvokeMarkItDown); - public bool IsMet => IsInstalled.Value; - - public string SkipReason => "MarkItDown is not installed or not accessible."; - private static bool CanInvokeMarkItDown() { ProcessStartInfo startInfo = new() diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownReaderTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownReaderTests.cs index e506ea15ca1..a9a99a4b947 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownReaderTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkItDownReaderTests.cs @@ -1,21 +1,21 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Linq; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.DataIngestion.Readers.Tests; -[MarkItDownCondition] public class MarkItDownReaderTests : DocumentReaderConformanceTests { protected override IngestionDocumentReader CreateDocumentReader(bool extractImages = false) - => MarkItDownConditionAttribute.IsInstalled.Value - ? new MarkItDownReader(extractImages: extractImages) - : throw new SkipTestException("MarkItDown is not installed"); + { + Assert.SkipUnless(MarkItDownConditionHelper.IsInstalled.Value, "MarkItDown is not installed"); + + return new MarkItDownReader(extractImages: extractImages); + } protected override void SimpleAsserts(IngestionDocument document, string source, string expectedId) { @@ -40,7 +40,7 @@ protected override void SimpleAsserts(IngestionDocument document, string source, // The original purpose of the MarkItDown library was to support text-only LLMs. // Source: https://github.com/microsoft/markitdown/issues/56#issuecomment-2546357264 // It can extract images, but the support is limited to some formats like docx. - [ConditionalFact] + [Fact] public override Task SupportsImages() => SupportsImagesCore( new("https://winprotocoldocs-bhdugrdyduf5h2e4.b02.azurefd.net/MC-SQLR/%5bMC-SQLR%5d-240423.docx")); // SQL Server Resolution Protocol. } diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkdownReaderTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkdownReaderTests.cs index 0e0ac10ca91..a93b5cd4c43 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkdownReaderTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Readers/MarkdownReaderTests.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Linq; using System.Threading.Tasks; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.DataIngestion.Readers.Tests; @@ -19,15 +18,15 @@ public class MarkdownReaderTests : DocumentReaderConformanceTests "https://raw.githubusercontent.com/microsoft/markitdown/main/README.md" ]; - [ConditionalTheory] + [Theory] [MemberData(nameof(Links))] public override Task SupportsStreams(string source) => base.SupportsStreams(source); - [ConditionalTheory] + [Theory] [MemberData(nameof(Links))] public override Task SupportsFiles(string source) => base.SupportsFiles(source); - [ConditionalFact] + [Fact] public override async Task SupportsTables() { string markdownContent = """ @@ -59,7 +58,7 @@ public override async Task SupportsTables() Assert.Equal(expected, documentTable.Cells.Map(element => element!.GetMarkdown().Trim())); } - [ConditionalFact] + [Fact] public async Task SupportsTablesWithoutTrailingPipes() { // Markdown tables without trailing pipes (|) at the end of each row should be parsed correctly. @@ -100,7 +99,7 @@ public async Task SupportsTablesWithoutTrailingPipes() Assert.Null(documentTable.Cells[3, 2]); // Empty description cell is null } - [ConditionalFact] + [Fact] public override async Task SupportsImages() { string contentType1 = "image/png"; @@ -142,7 +141,7 @@ JPEG is also fine! Assert.Equal("Three", images[2].AlternativeText); } - [ConditionalFact] + [Fact] public async Task SupportsTablesWithImages() { byte[] imageBytes = Enumerable.Range(55, 111).Select(i => (byte)i).ToArray(); @@ -174,7 +173,7 @@ public async Task SupportsTablesWithImages() Assert.Equal("Latest logo", img.AlternativeText); } - [ConditionalFact] + [Fact] public async Task SupportsInlineHtml() { string markdownContent = "This has [1] inline HTML."; @@ -186,7 +185,7 @@ public async Task SupportsInlineHtml() Assert.Equal(markdownContent, paragraph.GetMarkdown()); } - [ConditionalFact] + [Fact] public async Task SupportsMultipleInlineHtmlElements() { string markdownContent = """ diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/InMemoryVectorStoreWriterTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/InMemoryVectorStoreWriterTests.cs index b81b5a2aa79..f9767414976 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/InMemoryVectorStoreWriterTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/InMemoryVectorStoreWriterTests.cs @@ -1,8 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using CommunityToolkit.VectorData.InMemory; using Microsoft.Extensions.VectorData; -using Microsoft.SemanticKernel.Connectors.InMemory; namespace Microsoft.Extensions.DataIngestion.Writers.Tests; diff --git a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/SqliteVectorStoreWriterTests.cs b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/SqliteVectorStoreWriterTests.cs index b596445b822..7f29da9358d 100644 --- a/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/SqliteVectorStoreWriterTests.cs +++ b/test/Libraries/Microsoft.Extensions.DataIngestion.Tests/Writers/SqliteVectorStoreWriterTests.cs @@ -3,8 +3,8 @@ using System; using System.IO; +using CommunityToolkit.VectorData.SqliteVec; using Microsoft.Extensions.VectorData; -using Microsoft.SemanticKernel.Connectors.SqliteVec; namespace Microsoft.Extensions.DataIngestion.Writers.Tests; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Linux/LinuxResourceHealthCheckTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Linux/LinuxResourceHealthCheckTests.cs index 3b48570e8b7..233ad42fd6e 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Linux/LinuxResourceHealthCheckTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Linux/LinuxResourceHealthCheckTests.cs @@ -4,12 +4,12 @@ using System; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Diagnostics.ResourceMonitoring; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux; using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; -using Microsoft.TestUtilities; using Moq; using Xunit; @@ -142,14 +142,15 @@ public class LinuxResourceHealthCheckTests }, }; - [ConditionalTheory] + [Theory] [MemberData(nameof(Data))] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux-specific test.")] public async Task TestCpuAndMemoryChecks_WithMetrics( HealthStatus expected, double utilization, ulong memoryUsed, ulong totalMemory, ResourceUsageThresholds cpuThresholds, ResourceUsageThresholds memoryThresholds, string expectedDescription) { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux-specific test."); + var fakeClock = new FakeTimeProvider(); var dataTracker = new Mock(); var logger = new FakeLogger(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests.csproj b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests.csproj index dcd6d4e40db..d1efa82e4e6 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests.csproj @@ -6,7 +6,6 @@ - @@ -15,7 +14,7 @@ - + diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/ResourceHealthCheckExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/ResourceHealthCheckExtensionsTests.cs index 44083e56f6d..114e3690026 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/ResourceHealthCheckExtensionsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.HealthChecks.ResourceUtilization.Tests/ResourceHealthCheckExtensionsTests.cs @@ -1,9 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics.Metrics; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -13,17 +14,20 @@ using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Options; using Microsoft.Extensions.Time.Testing; -using Microsoft.TestUtilities; using Moq; using Xunit; using static Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Interop.JobObjectInfo; namespace Microsoft.Extensions.Diagnostics.HealthChecks.Test; -[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] public class ResourceHealthCheckExtensionsTests { - [ConditionalFact] + public ResourceHealthCheckExtensionsTests() + { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Skipped on macOS"); + } + + [Fact] public async Task AddResourceHealthCheck() { var dataTracker = new Mock(); @@ -43,7 +47,7 @@ public async Task AddResourceHealthCheck() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithCustomResourceMonitorAddedAfterInternalResourceMonitor_OverridesIt() { var dataTracker = new Mock(); @@ -63,7 +67,7 @@ public async Task AddResourceHealthCheck_WithCustomResourceMonitorAddedAfterInte dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_RegistersInternalResourceMonitoring() { var dataTracker = new Mock(); @@ -87,7 +91,7 @@ public void AddResourceHealthCheck_RegistersInternalResourceMonitoring() Assert.NotNull(resourceMonitoringOptions); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithTags() { var dataTracker = new Mock(); @@ -107,7 +111,7 @@ public async Task AddResourceHealthCheck_WithTags() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithTags_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -122,7 +126,7 @@ public void AddResourceHealthCheck_WithTags_RegistersInternalResourceMonitoring( Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithTags_WithCustomResourceMonitorAddedAfterInternalResourceMonitor_OverridesIt() { var dataTracker = new Mock(); @@ -142,7 +146,7 @@ public async Task AddResourceHealthCheck_WithTags_WithCustomResourceMonitorAdded dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithTagsEnumerable() { var dataTracker = new Mock(); @@ -162,7 +166,7 @@ public async Task AddResourceHealthCheck_WithTagsEnumerable() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithTagsEnumerable_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -177,7 +181,7 @@ public void AddResourceHealthCheck_WithTagsEnumerable_RegistersInternalResourceM Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithAction() { var dataTracker = new Mock(); @@ -200,7 +204,7 @@ public async Task AddResourceHealthCheck_WithAction() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithAction_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -218,7 +222,7 @@ public void AddResourceHealthCheck_WithAction_RegistersInternalResourceMonitorin Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithActionAndTags() { var dataTracker = new Mock(); @@ -242,7 +246,7 @@ public async Task AddResourceHealthCheck_WithActionAndTags() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithActionAndTags_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -261,7 +265,7 @@ public void AddResourceHealthCheck_WithActionAndTags_RegistersInternalResourceMo Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithActionAndTagsEnumerable() { var dataTracker = new Mock(); @@ -285,7 +289,7 @@ public async Task AddResourceHealthCheck_WithActionAndTagsEnumerable() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithActionAndTagsEnumerable_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -304,7 +308,7 @@ public void AddResourceHealthCheck_WithActionAndTagsEnumerable_RegistersInternal Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithConfigurationSection() { var dataTracker = new Mock(); @@ -323,7 +327,7 @@ public async Task AddResourceHealthCheck_WithConfigurationSection() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithConfigurationSection_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -338,7 +342,7 @@ public void AddResourceHealthCheck_WithConfigurationSection_RegistersInternalRes Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithConfigurationSectionAndTags() { var dataTracker = new Mock(); @@ -359,7 +363,7 @@ public async Task AddResourceHealthCheck_WithConfigurationSectionAndTags() dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithConfigurationSectionAndTags_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -375,7 +379,7 @@ public void AddResourceHealthCheck_WithConfigurationSectionAndTags_RegistersInte Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public async Task AddResourceHealthCheck_WithConfigurationSectionAndTagsEnumerable() { var dataTracker = new Mock(); @@ -396,7 +400,7 @@ public async Task AddResourceHealthCheck_WithConfigurationSectionAndTagsEnumerab dataTracker.Verify(tracker => tracker.GetUtilization(samplingWindow), Times.Once); } - [ConditionalFact] + [Fact] public void AddResourceHealthCheck_WithConfigurationSectionAndTagsEnumerable_RegistersInternalResourceMonitoring() { var serviceCollection = new ServiceCollection(); @@ -413,7 +417,7 @@ public void AddResourceHealthCheck_WithConfigurationSectionAndTagsEnumerable_Reg Assert.NotNull(resourceMonitor); } - [ConditionalFact] + [Fact] public void ConfigureResourceUtilizationHealthCheck_WithAction() { TimeSpan samplingWindow = TimeSpan.FromSeconds(1); @@ -435,7 +439,7 @@ public void ConfigureResourceUtilizationHealthCheck_WithAction() Assert.Equal(0.4, options.CpuThresholds.UnhealthyUtilizationPercentage); } - [ConditionalFact] + [Fact] public void ConfigureResourceUtilizationHealthCheck_WithConfigurationSection() { TimeSpan samplingWindow = TimeSpan.FromSeconds(5); @@ -464,14 +468,15 @@ public void TestNullChecks() Assert.Throws(() => ((IHealthChecksBuilder)null!).AddResourceUtilizationHealthCheck((IConfigurationSection)null!)); } - [ConditionalTheory] + [Theory] [ClassData(typeof(HealthCheckTestData))] - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows-specific test.")] public async Task TestCpuAndMemoryChecks_WithMetrics( HealthStatus expected, double utilization, ulong memoryUsed, ulong totalMemory, ResourceUsageThresholds cpuThresholds, ResourceUsageThresholds memoryThresholds, string expectedDescription) { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Windows-specific test."); + var logger = new FakeLogger(); var fakeClock = new FakeTimeProvider(); var dataTracker = new Mock(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Probes.Tests/Microsoft.Extensions.Diagnostics.Probes.Tests.csproj b/test/Libraries/Microsoft.Extensions.Diagnostics.Probes.Tests/Microsoft.Extensions.Diagnostics.Probes.Tests.csproj index 6e1c0cdf3fb..5f363b88ed2 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Probes.Tests/Microsoft.Extensions.Diagnostics.Probes.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Probes.Tests/Microsoft.Extensions.Diagnostics.Probes.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Linux/AcceptanceTest.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Linux/AcceptanceTest.cs index 4db8794a29f..9bf3db7de4f 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Linux/AcceptanceTest.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Linux/AcceptanceTest.cs @@ -1,8 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.Metrics; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Diagnostics.Metrics.Testing; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes; @@ -10,15 +11,18 @@ using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Linux; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public class AcceptanceTest { + public AcceptanceTest() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + [Fact] public async Task LinuxUtilizationProvider_MeasuredWithKubernetesMetadata() { diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests.csproj b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests.csproj index e964e6aa3e0..4481bc72c95 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes.Tests.csproj @@ -1,4 +1,4 @@ - + Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test @@ -10,10 +10,9 @@ - - + diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/AcceptanceTest.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/AcceptanceTest.cs index 8c7d9acf373..02a72ab61bc 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/AcceptanceTest.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/AcceptanceTest.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,9 +6,10 @@ using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Metrics; using System.IO; -#if !NET10_0 +#if !NET10_0_OR_GREATER using System.Linq; #endif +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Configuration; @@ -19,17 +20,17 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; public sealed class AcceptanceTest { - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] public void Adding_Linux_Resource_Utilization_Allows_To_Query_Snapshot_Provider() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + using var services = new ServiceCollection() .AddResourceMonitoring() .BuildServiceProvider(); @@ -40,11 +41,12 @@ public void Adding_Linux_Resource_Utilization_Allows_To_Query_Snapshot_Provider( Assert.NotEqual(default, provider.GetSnapshot()); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] [SuppressMessage("Minor Code Smell", "S3257:Declarations and initializations should be as concise as possible", Justification = "Broken analyzer.")] public void Adding_Linux_Resource_Utilization_Can_Be_Configured_With_Section() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); @@ -70,10 +72,11 @@ public void Adding_Linux_Resource_Utilization_Can_Be_Configured_With_Section() Assert.Equal(memoryRefresh, options.Value.MemoryConsumptionRefreshInterval); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] public void Adding_Linux_Resource_Utilization_Can_Be_Configured_With_Action() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); @@ -92,11 +95,12 @@ public void Adding_Linux_Resource_Utilization_Can_Be_Configured_With_Action() Assert.Equal(memoryRefresh, options.Value.MemoryConsumptionRefreshInterval); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] [SuppressMessage("Minor Code Smell", "S3257:Declarations and initializations should be as concise as possible", Justification = "Broken analyzer.")] public void Adding_Linux_Resource_Utilization_With_Section_Registers_SnapshotProvider_Cgroupv1() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); @@ -141,11 +145,12 @@ public void Adding_Linux_Resource_Utilization_With_Section_Registers_SnapshotPro Assert.Equal(100_000UL, provider.Resources.MaximumMemoryInBytes); } - [ConditionalFact] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] [SuppressMessage("Minor Code Smell", "S3257:Declarations and initializations should be as concise as possible", Justification = "Broken analyzer.")] public void Adding_Linux_Resource_Utilization_With_Section_Registers_SnapshotProvider_Cgroupv2() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); @@ -190,11 +195,11 @@ public void Adding_Linux_Resource_Utilization_With_Section_Registers_SnapshotPro Assert.Equal(100_000UL, provider.Resources.MaximumMemoryInBytes); } - [ConditionalFact] - [CombinatorialData] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] public Task ResourceUtilizationTracker_And_Metrics_Report_Same_Values_With_Cgroupsv1() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); var fileSystem = new HardcodedValueFileSystem(new Dictionary @@ -289,11 +294,11 @@ public Task ResourceUtilizationTracker_And_Metrics_Report_Same_Values_With_Cgrou return Task.CompletedTask; } - [ConditionalFact] - [CombinatorialData] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] public Task ResourceUtilizationTracker_And_Metrics_Report_Same_Values_With_Cgroupsv2() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var cpuRefresh = TimeSpan.FromMinutes(13); var memoryRefresh = TimeSpan.FromMinutes(14); var fileSystem = new HardcodedValueFileSystem(new Dictionary @@ -398,11 +403,11 @@ public Task ResourceUtilizationTracker_And_Metrics_Report_Same_Values_With_Cgrou return Task.CompletedTask; } - [ConditionalFact] - [CombinatorialData] - [OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] + [Fact] public Task ResourceUtilizationTracker_And_Metrics_Report_Same_Values_With_Cgroupsv2_Using_LinuxCalculationV2() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Linux specific tests"); + var fileSystem = new HardcodedValueFileSystem(new Dictionary { { new FileInfo("/proc/self/cgroup"), "0::/fakeslice"}, diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/DiskStatsReaderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/DiskStatsReaderTests.cs index 1f7738bb030..7ccf2477646 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/DiskStatsReaderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/DiskStatsReaderTests.cs @@ -1,18 +1,23 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Disk.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public class DiskStatsReaderTests { + public DiskStatsReaderTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + private static readonly string[] _skipDevicePrefixes = new[] { "ram", "loop", "dm-" }; [Fact] diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/LinuxSystemDiskMetricsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/LinuxSystemDiskMetricsTests.cs index 80ebc818894..1276a86181a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/LinuxSystemDiskMetricsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Disk/LinuxSystemDiskMetricsTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,20 +6,24 @@ using System.Diagnostics.Metrics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.Metrics.Testing; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Disk.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public class LinuxSystemDiskMetricsTests { + public LinuxSystemDiskMetricsTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + private static readonly string[] _skipDevicePrefixes = new[] { "ram", "loop", "dm-" }; private readonly FakeLogger _fakeLogger = new(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxNetworkMetricsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxNetworkMetricsTests.cs index 40536a3245c..e6c001d5f78 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxNetworkMetricsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxNetworkMetricsTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,17 +6,16 @@ using System.Diagnostics.Metrics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Network; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public class LinuxNetworkMetricsTests { private readonly Mock _tcpStateInfoProvider = new(); @@ -25,6 +24,8 @@ public class LinuxNetworkMetricsTests public LinuxNetworkMetricsTests() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + _timeProvider = new FakeTimeProvider(_startTime); _tcpStateInfoProvider.Setup(p => p.GetIpV4TcpStateInfo()).Returns(new TcpStateInfo()); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV1Tests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV1Tests.cs index 3820ec254e0..52511de8157 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV1Tests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV1Tests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,18 +6,22 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Shared.Pools; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public sealed class LinuxUtilizationParserCgroupV1Tests { - [ConditionalTheory] + public LinuxUtilizationParserCgroupV1Tests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + + [Theory] [InlineData("DFIJEUWGHFWGBWEFWOMDOWKSLA")] [InlineData("")] [InlineData("________________________Asdasdasdas dd")] @@ -40,7 +44,7 @@ public void Parser_Throws_When_Data_Is_Invalid(string line) Assert.Throws(() => parser.GetCgroupRequestCpuV2()); } - [ConditionalFact] + [Fact] public void Parser_Can_Read_Host_And_Cgroup_Available_Cpu_Count() { var parser = new LinuxUtilizationParserCgroupV1(new FileNamesOnlyFileSystem(TestResources.TestFilesLocation), new FakeUserHz(100)); @@ -51,7 +55,7 @@ public void Parser_Can_Read_Host_And_Cgroup_Available_Cpu_Count() Assert.Equal(1.0, cgroupCpuCount); } - [ConditionalFact] + [Fact] public void Parser_Provides_Total_Available_Memory_In_Bytes() { var fs = new FileNamesOnlyFileSystem(TestResources.TestFilesLocation); @@ -62,7 +66,7 @@ public void Parser_Provides_Total_Available_Memory_In_Bytes() Assert.Equal(16_233_760UL * 1024, totalMem); } - [ConditionalTheory] + [Theory] [InlineData("----------------------")] [InlineData("@ @#dddada")] [InlineData("1231234124124")] @@ -88,12 +92,13 @@ public void When_Calling_GetMemoryUsageInBytes_Parser_Throws_When_MemoryStat_Doe var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/memory/memory.stat", r.Message); Assert.Contains("total_inactive_file", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("----------------------")] [InlineData("@ @#dddada")] [InlineData("_1231234124124")] @@ -115,11 +120,12 @@ public void When_Calling_GetMemoryUsageInBytes_Parser_Throws_When_UsageInBytes_D var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/memory/memory.usage_in_bytes", r.Message); } - [ConditionalTheory] + [Theory] [InlineData(10, 1)] [InlineData(23, 22)] [InlineData(100000, 10000)] @@ -134,11 +140,12 @@ public void When_Calling_GetMemoryUsageInBytes_Parser_Throws_When_Inactive_Memor var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("lesser than", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("Mem")] [InlineData("MemTotal:")] [InlineData("MemTotal: 120")] @@ -160,11 +167,12 @@ public void When_Calling_GetHostAvailableMemory_Parser_Throws_When_MemInfo_Does_ var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetHostAvailableMemory()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/proc/meminfo", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("kB", 231, 236544)] [InlineData("MB", 287, 300_941_312)] [InlineData("GB", 372, 399_431_958_528)] @@ -183,7 +191,7 @@ public void When_Calling_GetHostAvailableMemory_Parser_Correctly_Transforms_Supp Assert.Equal(bytes, memory); } - [ConditionalTheory] + [Theory] [InlineData("0-11", 12)] [InlineData("0", 1)] [InlineData("1000", 1)] @@ -210,7 +218,7 @@ public void When_No_Cgroup_Cpu_Limits_Are_Not_Set_We_Get_Available_Cpus_From_Cpu Assert.Equal(result, cpus); } - [ConditionalTheory] + [Theory] [InlineData("-11")] [InlineData("0-")] [InlineData("d-22")] @@ -234,11 +242,12 @@ public void Parser_Throws_When_CpuSet_Has_Invalid_Content(string content) var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupLimitedCpus()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/cpuset/cpuset.cpus", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("-1", "18")] [InlineData("18", "-1")] [InlineData("18", "")] @@ -255,11 +264,12 @@ public void When_Quota_And_Period_Are_Minus_One_It_Fallbacks_To_Cpuset(string qu var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupLimitedCpus()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/cpuset/cpuset.cpus", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("dd1d", "18")] [InlineData("-18", "18")] [InlineData("\r\r\r\r\r", "18")] @@ -283,11 +293,12 @@ public void Parser_Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data(string quot var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupLimitedCpus()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/cpu/cpu.cfs_", r.Message); } - [ConditionalFact] + [Fact] public void ReadingCpuUsage_Does_Not_Throw_For_Valid_Input() { var f = new HardcodedValueFileSystem(new Dictionary @@ -301,7 +312,7 @@ public void ReadingCpuUsage_Does_Not_Throw_For_Valid_Input() Assert.Null(r); } - [ConditionalFact] + [Fact] public void ReadingTotalMemory_Does_Not_Throw_For_Valid_Input() { var f = new HardcodedValueFileSystem(new Dictionary @@ -316,7 +327,7 @@ public void ReadingTotalMemory_Does_Not_Throw_For_Valid_Input() Assert.Null(r); } - [ConditionalTheory] + [Theory] [InlineData("2569530367000")] [InlineData(" 2569530 36700 245693 4860924 82283 0 4360 0dsa 0 0 asdasd @@@@")] [InlineData("asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0")] @@ -333,11 +344,12 @@ public void ReadingCpuUsage_Does_Throws_For_Valid_Input(string content) var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetHostCpuUsageInNanoseconds()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("proc/stat", r.Message); } - [ConditionalTheory] + [Theory] [InlineData("-1")] [InlineData("")] public void Parser_Throws_When_Cgroup_Cpu_Shares_Files_Contain_Invalid_Data(string content) @@ -350,11 +362,12 @@ public void Parser_Throws_When_Cgroup_Cpu_Shares_Files_Contain_Invalid_Data(stri var p = new LinuxUtilizationParserCgroupV1(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupRequestCpu()); + Assert.NotNull(r); Assert.IsAssignableFrom(r); Assert.Contains("/sys/fs/cgroup/cpu/cpu.shares", r.Message); } - [ConditionalFact] + [Fact] public async Task ThreadSafetyAsync() { var f1 = new HardcodedValueFileSystem(new Dictionary diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV2Tests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV2Tests.cs index 648b5e5afc6..2e62afa8f21 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV2Tests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationParserCgroupV2Tests.cs @@ -1,25 +1,29 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Shared.Pools; -using Microsoft.TestUtilities; using Moq; using VerifyXunit; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public sealed class LinuxUtilizationParserCgroupV2Tests { + public LinuxUtilizationParserCgroupV2Tests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + private const string VerifiedDataDirectory = "Verified"; - [ConditionalTheory] + [Theory] [InlineData("DFIJEUWGHFWGBWEFWOMDOWKSLA")] [InlineData("")] [InlineData("________________________Asdasdasdas dd")] @@ -43,7 +47,7 @@ public void Throws_When_Data_Is_Invalid(string line) Assert.Throws(() => parser.GetCgroupPeriodsIntervalInMicroSecondsV2()); } - [ConditionalFact] + [Fact] public void Can_Read_Host_And_Cgroup_Available_Cpu_Count() { var parser = new LinuxUtilizationParserCgroupV2(new FileNamesOnlyFileSystem(TestResources.TestFilesLocation), new FakeUserHz(100)); @@ -54,7 +58,7 @@ public void Can_Read_Host_And_Cgroup_Available_Cpu_Count() Assert.Equal(2.0, cgroupCpuCount); } - [ConditionalFact] + [Fact] public void Provides_Total_Available_Memory_In_Bytes() { var fs = new FileNamesOnlyFileSystem(TestResources.TestFilesLocation); @@ -65,7 +69,7 @@ public void Provides_Total_Available_Memory_In_Bytes() Assert.Equal(16_233_760UL * 1024, totalMem); } - [ConditionalTheory] + [Theory] [InlineData("----------------------")] [InlineData("@ @#dddada")] [InlineData("1231234124124")] @@ -92,10 +96,11 @@ public Task Throws_When_TotalInactiveFile_Is_Invalid(string content) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("----------------------")] [InlineData("@ @#dddada")] [InlineData("_1231234124124")] @@ -117,10 +122,11 @@ public Task Throws_When_UsageInBytes_Is_Invalid(string content) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("max\n", 134_796_910_592ul)] [InlineData("1000000\n", 1_000_000ul)] public void Returns_Available_Memory_When_AvailableMemoryInBytes_Is_Valid(string content, ulong expectedResult) @@ -137,7 +143,7 @@ public void Returns_Available_Memory_When_AvailableMemoryInBytes_Is_Valid(string Assert.Equal(expectedResult, result); } - [ConditionalTheory] + [Theory] [InlineData("Suspicious12312312")] [InlineData("string@")] [InlineData("string12312")] @@ -151,10 +157,11 @@ public Task Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number(stri var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetAvailableMemoryInBytes()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalFact] + [Fact] public Task Throws_When_UsageInBytes_Doesnt_Contain_A_Number() { var regexPatternforSlices = @"\w+.slice"; @@ -166,10 +173,11 @@ public Task Throws_When_UsageInBytes_Doesnt_Contain_A_Number() var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytesFromSlices(regexPatternforSlices)); + Assert.NotNull(r); return Verifier.Verify(r).UseDirectory(VerifiedDataDirectory); } - [ConditionalFact] + [Fact] public void Returns_Memory_Usage_When_Memory_Usage_Is_Valid() { // When memory usage is a positive number @@ -195,7 +203,7 @@ public void Returns_Memory_Usage_When_Memory_Usage_Is_Valid() Assert.Equal(0, r); } - [ConditionalTheory] + [Theory] [InlineData(104343, 1)] [InlineData(23423, 22)] [InlineData(10000, 100)] @@ -210,10 +218,11 @@ public Task Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory(int inactive var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetMemoryUsageInBytes()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(inactive, total).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("Mem")] [InlineData("MemTotal:")] [InlineData("MemTotal: 120")] @@ -235,10 +244,11 @@ public Task Throws_When_MemInfo_Does_Not_Contain_TotalMemory(string totalMemory) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetHostAvailableMemory()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(totalMemory).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("kB", 231, 236_544)] [InlineData("MB", 287, 300_941_312)] [InlineData("GB", 372, 399_431_958_528)] @@ -256,7 +266,7 @@ public void Transforms_Supported_Units_To_Bytes(string unit, int value, ulong by Assert.Equal(bytes, memory); } - [ConditionalTheory] + [Theory] [InlineData("0-11", 12)] [InlineData("0", 1)] [InlineData("1000", 1)] @@ -282,7 +292,7 @@ public void Gets_Available_Cpus_From_CpuSetCpus_When_Cpu_Limits_Not_Set(string c Assert.Equal(result, cpus); } - [ConditionalTheory] + [Theory] [InlineData("0::/")] [InlineData("0::/fakeslice")] public void Gets_Available_Cpus_From_CpuSetCpusFromSlices_When_Cpu_Limits_Not_Set(string slicepath) @@ -300,7 +310,7 @@ public void Gets_Available_Cpus_From_CpuSetCpusFromSlices_When_Cpu_Limits_Not_Se Assert.Equal(2, cpus); } - [ConditionalTheory] + [Theory] [InlineData("100", 1)] [InlineData("1", 0.001953125)] [InlineData("10000", 256)] @@ -320,7 +330,7 @@ public void Calculates_Cpu_Request_From_Cpu_WeightInSlices(string content, float } // Based on https://github.com/kubernetes/website/blob/main/content/en/blog/_posts/2026-01-30-new-cgroup-v1-to-v2-conversion-formula/index.md#new-conversion-formula - [ConditionalTheory] + [Theory] [InlineData("100", 1)] [InlineData("1", 0.001953125)] [InlineData("10000", 256)] @@ -338,7 +348,7 @@ public void Calculates_Cpu_Request_From_Cpu_Weight(string content, float result) Assert.Equal(result, r); } - [ConditionalFact] + [Fact] public void Gets_Available_Cpus_From_CpuSetCpus_When_Cpu_Max_Set_To_Max_() { var f = new HardcodedValueFileSystem(new Dictionary @@ -353,7 +363,7 @@ public void Gets_Available_Cpus_From_CpuSetCpus_When_Cpu_Max_Set_To_Max_() Assert.Equal(3, cpus); } - [ConditionalTheory] + [Theory] [InlineData("-11")] [InlineData("0-")] [InlineData("d-22")] @@ -376,10 +386,11 @@ public Task Throws_When_CpuSet_Has_Invalid_Content(string content) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetHostCpuCount()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalFact] + [Fact] public Task Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_() { var f = new HardcodedValueFileSystem(new Dictionary @@ -391,10 +402,11 @@ public Task Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_() var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupLimitedCpus()); + Assert.NotNull(r); return Verifier.Verify(r).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("dd1d", "18")] [InlineData("-18", "18")] [InlineData("\r\r\r\r\r", "18")] @@ -416,10 +428,11 @@ public Task Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data(string quota, stri var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupLimitedCpus()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(quota, period).UseDirectory(VerifiedDataDirectory); } - [ConditionalFact] + [Fact] public void Reads_CpuUsage_When_Valid_Input() { var f = new HardcodedValueFileSystem(new Dictionary @@ -433,7 +446,7 @@ public void Reads_CpuUsage_When_Valid_Input() Assert.Equal(77_994_900_000_000, r); } - [ConditionalTheory] + [Theory] [InlineData("0::/", "usage_usec 222222\nnr_periods 50", "222222000", "50")] [InlineData("0::/fakeslice", "usage_usec 222222\nnr_periods 75", "222222000", "75")] public void Reads_CpuUsageFromSlices_When_Valid_Input(string slicepath, string content, string expectedUsage, string expectedPeriods) @@ -454,7 +467,7 @@ public void Reads_CpuUsageFromSlices_When_Valid_Input(string slicepath, string c Assert.Equal(expectedPeriods, periods.ToString()); } - [ConditionalFact] + [Fact] public void Reads_TotalMemory_When_Valid_Input() { var f = new HardcodedValueFileSystem(new Dictionary @@ -469,7 +482,7 @@ public void Reads_TotalMemory_When_Valid_Input() Assert.Null(r); } - [ConditionalTheory] + [Theory] [InlineData("2569530367000")] [InlineData(" 2569530 36700 245693 4860924 82283 0 4360 0dsa")] [InlineData("asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0")] @@ -486,10 +499,11 @@ public Task Throws_When_CpuUsage_Invalid(string content) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetHostCpuUsageInNanoseconds()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("usage_", 12222)] [InlineData("dasd", -1)] [InlineData("@#dddada", 342322)] @@ -503,10 +517,11 @@ public Task Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts(string conte var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupCpuUsageInNanoseconds()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content, value).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData(-32131)] [InlineData(-1)] [InlineData(-15.323)] @@ -520,10 +535,11 @@ public Task Throws_When_Usage_Usec_Has_Negative_Value(int value) var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupCpuUsageInNanoseconds()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(value).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("-1")] [InlineData("dasrz3424")] [InlineData("0")] @@ -538,10 +554,11 @@ public Task Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data(string cont var p = new LinuxUtilizationParserCgroupV2(f, new FakeUserHz(100)); var r = Record.Exception(() => p.GetCgroupRequestCpu()); + Assert.NotNull(r); return Verifier.Verify(r).UseParameters(content).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [InlineData("0::/", "filename", "/sys/fs/cgroup/filename")] [InlineData("0::/filesystem.slice", "filename", "/sys/fs/cgroup/filesystem.slice/filename")] [InlineData("0::/filesystem.slice/", "filename", "/sys/fs/cgroup/filesystem.slice/filename")] @@ -558,7 +575,7 @@ public void Create_Path_From_Proc_Self_Cgroup(string content, string filename, s Assert.Equal(result, r); } - [ConditionalFact] + [Fact] public async Task Is_Thread_Safe_Async() { var f1 = new HardcodedValueFileSystem(new Dictionary diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationProviderTests.cs index 4e2a0008e7a..a820988e36c 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/LinuxUtilizationProviderTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,25 +6,28 @@ using System.Diagnostics.Metrics; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using VerifyXunit; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public sealed class LinuxUtilizationProviderTests { + public LinuxUtilizationProviderTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + private const string VerifiedDataDirectory = "Verified"; - [ConditionalFact] - [CombinatorialData] + [Fact] public void Provider_Registers_Instruments() { var meterName = Guid.NewGuid().ToString(); @@ -108,8 +111,7 @@ public void Provider_Registers_Instruments() Assert.Equal(0.5, samples.Single(i => i.instrument.Name == ResourceUtilizationInstruments.ProcessMemoryUtilization).value); } - [ConditionalFact] - [CombinatorialData] + [Fact] public void Provider_Registers_Instruments_CgroupV2() { var meterName = Guid.NewGuid().ToString(); @@ -182,7 +184,7 @@ public void Provider_Registers_Instruments_CgroupV2() Assert.Equal(1, samples.Single(i => i.instrument.Name == ResourceUtilizationInstruments.ProcessMemoryUtilization).value); } - [ConditionalFact] + [Fact] public Task Provider_EmitsLogRecord() { var meterName = Guid.NewGuid().ToString(); @@ -229,8 +231,7 @@ public void Provider_Creates_Meter_With_Correct_Name() Assert.Equal(ResourceUtilizationInstruments.MeterName, meter.Name); } - [ConditionalFact] - [CombinatorialData] + [Fact] public void Provider_Registers_Instruments_CgroupV2_WithoutHostCpu() { var meterName = Guid.NewGuid().ToString(); @@ -436,7 +437,7 @@ public void Provider_GetMeasurementWithRetry_UnhandledException_DoesNotBlockFutu parserMock.Verify(p => p.GetMemoryUsageInBytes(), Times.Exactly(5)); } - [ConditionalFact] + [Fact] public void Provider_WithZeroToOneRangeFalse_AndCalculationV1_ReturnsHundredBasedValues() { var logger = new FakeLogger(); @@ -513,7 +514,7 @@ public void Provider_WithZeroToOneRangeFalse_AndCalculationV1_ReturnsHundredBase Assert.Equal(1_048_576, memoryUsage); } - [ConditionalFact] + [Fact] public void Provider_WithZeroToOneRangeTrue_AndCalculationV1_ReturnsNormalizedValues() { var logger = new FakeLogger(); @@ -590,7 +591,7 @@ public void Provider_WithZeroToOneRangeTrue_AndCalculationV1_ReturnsNormalizedVa Assert.Equal(1_048_576, memoryUsage); } - [ConditionalFact] + [Fact] public void Provider_WithZeroToOneRangeFalse_AndCalculationV2_ReturnsHundredBasedValues() { var logger = new FakeLogger(); @@ -663,7 +664,7 @@ public void Provider_WithZeroToOneRangeFalse_AndCalculationV2_ReturnsHundredBase } } - [ConditionalFact] + [Fact] public void Provider_WithZeroToOneRangeTrue_AndCalculationV2_ReturnsNormalizedValues() { var logger = new FakeLogger(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/OSFileSystemTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/OSFileSystemTests.cs index 9746d8395a5..9c81e144a53 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/OSFileSystemTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/OSFileSystemTests.cs @@ -1,20 +1,24 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using Microsoft.Shared.Pools; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test; -[OSSkipCondition(OperatingSystems.Windows | OperatingSystems.MacOSX, SkipReason = "Linux specific tests")] public sealed class OSFileSystemTests { - [ConditionalFact] + public OSFileSystemTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Skipped on Windows/macOS"); + } + + [Fact] public void GetDirectoryNames_ReturnsDirectoryNames() { var fileSystem = new OSFileSystem(); @@ -24,7 +28,7 @@ public void GetDirectoryNames_ReturnsDirectoryNames() Assert.Single(directoryNames); } - [ConditionalFact] + [Fact] public void Reading_First_File_Line_Works() { const string Content = "Name: cat"; @@ -37,7 +41,7 @@ public void Reading_First_File_Line_Works() Assert.Equal(Content, s); } - [ConditionalFact] + [Fact] public void Reading_The_Whole_File_Works() { const string Content = "user 1399428\nsystem 1124053\n"; @@ -51,7 +55,7 @@ public void Reading_The_Whole_File_Works() Assert.Equal(Content, s); } - [ConditionalTheory] + [Theory] [InlineData(128)] [InlineData(256)] [InlineData(512)] diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_.verified.txt index 82d8bb138d3..3ed341942c1 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Fallsback_To_Cpuset_When_Quota_And_Period_Are_Minus_One_.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=Suspicious12312312.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=Suspicious12312312.verified.txt index 519fc8895fd..58ac412fe41 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=Suspicious12312312.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=Suspicious12312312.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetAvailableMemoryInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass7_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass8_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string12312.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string12312.verified.txt index 07eeba1bd3b..362dcc800a7 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string12312.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string12312.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetAvailableMemoryInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass7_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass8_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string@.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string@.verified.txt index df74fcb7f6b..5261275f803 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string@.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_AvailableMemoryInBytes_Doesnt_Contain_Just_A_Number_content=string@.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetAvailableMemoryInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass7_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass8_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota= 12_period=eeeee 12.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota= 12_period=eeeee 12.verified.txt index 9a9c5ea6de9..656deef01ea 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota= 12_period=eeeee 12.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota= 12_period=eeeee 12.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-----_period=18.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-----_period=18.verified.txt index 9aee65c954b..80257b5b298 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-----_period=18.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-----_period=18.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-18_period=18.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-18_period=18.verified.txt index 1614c75cf96..7ef41fc1efd 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-18_period=18.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-18_period=18.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d'.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d'.verified.txt index f65e4249d0d..08c322b630b 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d'.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d'.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d--.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d--.verified.txt index 2121db86442..6a310a820a6 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d--.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=-_period=d--.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=12 _period=.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=12 _period=.verified.txt index 96bd7cb60d9..512b88aeb8e 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=12 _period=.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=12 _period=.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=123_period=-----.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=123_period=-----.verified.txt index d607b4745c3..45728ace321 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=123_period=-----.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=123_period=-----.verified.txt @@ -12,6 +12,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2_period=d--.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2_period=d--.verified.txt index d6cdc99caf1..eaad72ae405 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2_period=d--.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2_period=d--.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2d2d2d_period=e3.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2d2d2d_period=e3.verified.txt index de12fed2796..387dd2b0339 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2d2d2d_period=e3.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=2d2d2d_period=e3.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=3d_period=d3.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=3d_period=d3.verified.txt index 046d18f684d..2ee34a85d57 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=3d_period=d3.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=3d_period=d3.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=dd1d_period=18.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=dd1d_period=18.verified.txt index f8d4d74e76f..04c8737f9dd 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=dd1d_period=18.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Files_Contain_Invalid_Data_quota=dd1d_period=18.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuQuotaAndPeriodFromFile(IFileSystem fileSystem, FileInfo cpuLimitsFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCpuUnitsFromCgroups(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupLimitedCpus() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass20_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass21_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=-1.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=-1.verified.txt index f56573e48ff..83c765ead91 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=-1.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=-1.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuWeightFromFile(IFileSystem fileSystem, FileInfo cpuWeightFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCgroupRequestCpu(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupRequestCpu() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass28_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=0.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=0.verified.txt index 2a35a20c74c..c72625d04a9 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=0.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=0.verified.txt @@ -7,6 +7,6 @@ at Microsoft.Shared.Diagnostics.Throw.ArgumentOutOfRangeException(String paramNa at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuWeightFromFile(IFileSystem fileSystem, FileInfo cpuWeightFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCgroupRequestCpu(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupRequestCpu() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass28_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=10001.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=10001.verified.txt index aec4252bee4..324b7196f38 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=10001.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=10001.verified.txt @@ -7,6 +7,6 @@ at Microsoft.Shared.Diagnostics.Throw.ArgumentOutOfRangeException(String paramNa at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuWeightFromFile(IFileSystem fileSystem, FileInfo cpuWeightFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCgroupRequestCpu(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupRequestCpu() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass28_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=dasrz3424.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=dasrz3424.verified.txt index ac42893f11b..d1ac21aafd9 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=dasrz3424.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Cgroup_Cpu_Weight_Files_Contain_Invalid_Data_content=dasrz3424.verified.txt @@ -6,6 +6,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryParseCpuWeightFromFile(IFileSystem fileSystem, FileInfo cpuWeightFile, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.TryGetCgroupRequestCpu(IFileSystem fileSystem, Single& cpuUnits) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupRequestCpu() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass28_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=@#dddada_value=342322.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=@#dddada_value=342322.verified.txt index d786ad17825..9419237af61 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=@#dddada_value=342322.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=@#dddada_value=342322.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=dasd_value=-1.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=dasd_value=-1.verified.txt index d786ad17825..9419237af61 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=dasd_value=-1.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=dasd_value=-1.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=usage__value=12222.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=usage__value=12222.verified.txt index d786ad17825..9419237af61 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=usage__value=12222.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuAcctUsage_Has_Invalid_Content_Both_Parts_content=usage__value=12222.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content= d 182-1923.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content= d 182-1923.verified.txt index 083cf79c102..c3e753cef82 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content= d 182-1923.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content= d 182-1923.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=--.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=--.verified.txt index ccc00fca213..1349ac829da 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=--.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=--.verified.txt @@ -7,6 +7,6 @@ Could not parse '/sys/fs/cgroup/cpuset.cpus.effective'. Expected comma-separated at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=-11.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=-11.verified.txt index 293de58c5a6..c3e01e50db3 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=-11.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=-11.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=.verified.txt index 379a850ec3d..eba5e406ec8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=0-.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=0-.verified.txt index 282e0823cce..420fe1d5f65 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=0-.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=0-.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18 --.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18 --.verified.txt index a9471f74e73..d37ce8e7d25 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18 --.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18 --.verified.txt @@ -7,6 +7,6 @@ Could not parse '/sys/fs/cgroup/cpuset.cpus.effective'. Expected comma-separated at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18-22.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18-22.verified.txt index 59c1a6eca3f..13d8f0542f1 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18-22.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=1-18-22.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-18.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-18.verified.txt index 07781ffaca1..583183455c6 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-18.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-18.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-d.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-d.verified.txt index 323133e718e..ba39acfc602 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-d.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=22-d.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=aaaa.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=aaaa.verified.txt index e23d4e48ac3..c78d90d6d0c 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=aaaa.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=aaaa.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=d-22.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=d-22.verified.txt index f98ea80e149..2401381d790 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=d-22.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuSet_Has_Invalid_Content_content=d-22.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.g__ThrowException|35_0(ReadOnlySpan`1 content) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuCount() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass18_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass19_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2.verified.txt index e28c0894b1b..2ea726be837 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693 4860924 82283 0 4360 0dsa.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693 4860924 82283 0 4360 0dsa.verified.txt index 617677c76cc..1d829e0591a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693 4860924 82283 0 4360 0dsa.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693 4860924 82283 0 4360 0dsa.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693.verified.txt index 58d23f037b9..dd5550176ca 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content= 2569530 36700 245693.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=2569530367000.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=2569530367000.verified.txt index 35ca14c3aee..7754d980988 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=2569530367000.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=2569530367000.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0.verified.txt index 8d8db5314ae..a752cc06eed 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=asdasd 2569530 36700 245693 4860924 82283 0 4360 0 0 0.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=cpu 2569530 36700 245693.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=cpu 2569530 36700 245693.verified.txt index af3c4b40471..7e4873db67c 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=cpu 2569530 36700 245693.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_CpuUsage_Invalid_content=cpu 2569530 36700 245693.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass24_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass25_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=10000_total=100.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=10000_total=100.verified.txt index d63f70c4e25..138c3586335 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=10000_total=100.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=10000_total=100.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass10_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=104343_total=1.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=104343_total=1.verified.txt index d63f70c4e25..138c3586335 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=104343_total=1.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=104343_total=1.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass10_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=23423_total=22.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=23423_total=22.verified.txt index d63f70c4e25..138c3586335 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=23423_total=22.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Inactive_Memory_Is_Bigger_Than_Total_Memory_inactive=23423_total=22.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass10_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=Mem.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=Mem.verified.txt index 29de1770a02..bd8637200ad 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=Mem.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=Mem.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 .verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 .verified.txt index c2619dca15e..0ba138c8b09 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 .verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 .verified.txt @@ -3,6 +3,6 @@ Message: We tried to convert total memory usage value from '/proc/meminfo' to bytes, but we've got a unit that we don't recognize: ' '., StackTrace: at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 @@ .verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 @@ .verified.txt index c2619dca15e..0ba138c8b09 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 @@ .verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 @@ .verified.txt @@ -3,6 +3,6 @@ Message: We tried to convert total memory usage value from '/proc/meminfo' to bytes, but we've got a unit that we don't recognize: ' '., StackTrace: at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 PB.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 PB.verified.txt index 2c5d8955ab4..95806b39e32 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 PB.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 1024 PB.verified.txt @@ -3,6 +3,6 @@ Message: We tried to convert total memory usage value from '/proc/meminfo' to bytes, but we've got a unit that we don't recognize: 'PB'., StackTrace: at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 120.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 120.verified.txt index 1be58bfd10b..65e90c9013d 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 120.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- 120.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- MB.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- MB.verified.txt index 0bdab7d244c..6e3d2b560cc 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- MB.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- MB.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- PB.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- PB.verified.txt index 447f0a82770..5587cd4c2b8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- PB.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- PB.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- kb.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- kb.verified.txt index 84f69a64134..4ade73e9d9a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- kb.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal- kb.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal-.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal-.verified.txt index 332ecc6dca4..edef71b89eb 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal-.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemTotal-.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 1024 MB .verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 1024 MB .verified.txt index 8284a49d5d8..232bd1195fc 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 1024 MB .verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 1024 MB .verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 123123123123123123.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 123123123123123123.verified.txt index e69b398131f..82470bba90c 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 123123123123123123.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_MemInfo_Does_Not_Contain_TotalMemory_totalMemory=MemoryTotal- 123123123123123123.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetHostAvailableMemory() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass11_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass12_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=----------------------.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=----------------------.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=----------------------.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=----------------------.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=--.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=--.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=--.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=--.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB d -- 1024.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB d -- 1024.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB d -- 1024.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB d -- 1024.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1024 KB.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1231234124124.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1231234124124.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1231234124124.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=1231234124124.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=@ @#dddada.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=@ @#dddada.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=@ @#dddada.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=@ @#dddada.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Suspicious.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Suspicious.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Suspicious.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Suspicious.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Total_Inactive_File 2.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Total_Inactive_File 2.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Total_Inactive_File 2.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=Total_Inactive_File 2.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string12312.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string12312.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string12312.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string12312.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@ -1.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@ -1.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@ -1.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@ -1.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=string@.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total-inactive-file.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total-inactive-file.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total-inactive-file.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total-inactive-file.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_active_file.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_active_file.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_active_file.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_active_file.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive-file.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive-file.verified.txt index 6bf8086762a..2ff9ab7b6f8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive-file.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive-file.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive_file-_ 21391.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive_file-_ 21391.verified.txt index 6528add5dcd..0e57c45f5f1 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive_file-_ 21391.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_TotalInactiveFile_Is_Invalid_content=total_inactive_file-_ 21391.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass4_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Doesnt_Contain_A_Number.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Doesnt_Contain_A_Number.verified.txt index 1b94cfbe0a6..f9fe04b776e 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Doesnt_Contain_A_Number.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Doesnt_Contain_A_Number.verified.txt @@ -4,6 +4,6 @@ StackTrace: at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesFromSlices(String pattern) -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass8_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass9_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=----------------------.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=----------------------.verified.txt index 10571270f1b..8ee2b437e2f 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=----------------------.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=----------------------.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=--.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=--.verified.txt index 1a9ddd5c7e2..8bc3bfdb005 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=--.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=--.verified.txt @@ -8,6 +8,6 @@ We tried to read '/sys/fs/cgroup/memory.current', and we expected to get a posit at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=.verified.txt index cae459b47bb..294aa7e1511 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=@ @#dddada.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=@ @#dddada.verified.txt index 9a2c03c0777..21865ac944a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=@ @#dddada.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=@ @#dddada.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious.verified.txt index ced16503c22..669d9bcc64c 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious12312312.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious12312312.verified.txt index 63aa7898715..03d430e85b5 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious12312312.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=Suspicious12312312.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=_1231234124124.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=_1231234124124.verified.txt index 5cd1601ed29..ddbfd77389b 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=_1231234124124.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=_1231234124124.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=eee 1024 KB.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=eee 1024 KB.verified.txt index fc9f97b6e95..219b32b1f75 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=eee 1024 KB.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=eee 1024 KB.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string12312.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string12312.verified.txt index a377ea16586..eeaae1dd347 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string12312.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string12312.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string@.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string@.verified.txt index 58972b79802..8d6da962803 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string@.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_UsageInBytes_Is_Invalid_content=string@.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytesPod() at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetMemoryUsageInBytes() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass5_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass6_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } \ No newline at end of file diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-1.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-1.verified.txt index b17a7fb1f89..7756f002c41 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-1.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-1.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-15.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-15.verified.txt index 896c06edcba..d95112bac60 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-15.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-15.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-32131.verified.txt b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-32131.verified.txt index c8fbb5dba1b..5d88773608b 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-32131.verified.txt +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Linux/Verified/LinuxUtilizationParserCgroupV2Tests.Throws_When_Usage_Usec_Has_Negative_Value_value=-32131.verified.txt @@ -5,6 +5,6 @@ at Microsoft.Shared.Diagnostics.Throw.InvalidOperationException(String message) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.ParseCpuUsageFromFile(IFileSystem fileSystem, FileInfo cpuUsageFile) at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.LinuxUtilizationParserCgroupV2.GetCgroupCpuUsageInNanoseconds() -at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass26_0.b__0() +at Microsoft.Extensions.Diagnostics.ResourceMonitoring.Linux.Test.LinuxUtilizationParserCgroupV2Tests.<>c__DisplayClass27_0.b__0() at Xunit.Record.Exception(Func`1 testCode) } diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests.csproj b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests.csproj index ff2cd26412f..51873868aaa 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests.csproj @@ -1,11 +1,11 @@ - + Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test Unit tests for Microsoft.Extensions.Diagnostics.ResourceMonitoring true - + @@ -19,6 +19,5 @@ - diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringBuilderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringBuilderTests.cs index d2e3d5d8292..5960bd74f8a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringBuilderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringBuilderTests.cs @@ -1,18 +1,22 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Publishers; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test; -[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] public sealed class ResourceMonitoringBuilderTests { - [ConditionalFact(Skip = "Not supported on MacOs.")] + public ResourceMonitoringBuilderTests() + { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Skipped on macOS"); + } + + [Fact] public void AddPublisher_CalledOnce_AddsSinglePublisherToServiceCollection() { using var provider = new ServiceCollection() @@ -33,7 +37,7 @@ public void AddPublisher_CalledOnce_AddsSinglePublisherToServiceCollection() Assert.IsAssignableFrom(publishersArray.First()); } - [ConditionalFact] + [Fact] public void AddPublisher_CalledMultipleTimes_AddsMultiplePublishersToServiceCollection() { using var provider = new ServiceCollection() diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs index 875fbb67158..ed6d57f9e09 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/ResourceMonitoringExtensionsTests.cs @@ -1,9 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Providers; @@ -11,17 +12,17 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.Testing; using Microsoft.Extensions.Options; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test; public sealed class ResourceMonitoringExtensionsTests { - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void Throw_Null_When_Registration_Ingredients_Null() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + var services = new ServiceCollection(); Assert.Throws(() => ((IResourceMonitorBuilder)null!).ConfigureMonitor(_ => { })); @@ -30,10 +31,11 @@ public void Throw_Null_When_Registration_Ingredients_Null() Assert.Throws(() => services.AddResourceMonitoring((b) => b.ConfigureMonitor((Action)null!))); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void AddsResourceMonitoringService_ToServicesCollection() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + using var provider = new ServiceCollection() .AddLogging() .AddSingleton(TimeProvider.System) @@ -51,10 +53,11 @@ public void AddsResourceMonitoringService_ToServicesCollection() Assert.IsAssignableFrom(trackerService); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void AddsResourceMonitoringService_ToServicesCollection_NoArgs() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + using var provider = new ServiceCollection() .AddLogging() .AddSingleton(TimeProvider.System) @@ -68,10 +71,11 @@ public void AddsResourceMonitoringService_ToServicesCollection_NoArgs() Assert.IsAssignableFrom(trackerService); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void AddsResourceMonitoringService_AsHostedService() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + using var provider = new ServiceCollection() .AddLogging() .AddSingleton(TimeProvider.System) @@ -90,10 +94,11 @@ public void AddsResourceMonitoringService_AsHostedService() Assert.IsAssignableFrom(trackerService); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void ConfigureResourceUtilization_InitializeTrackerProperly() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + using var host = FakeHost.CreateBuilder() .ConfigureServices(services => { @@ -117,10 +122,11 @@ public void ConfigureResourceUtilization_InitializeTrackerProperly() Assert.NotNull(publisher); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void ConfigureMonitor_GivenOptionsDelegate_InitializeTrackerWithOptionsProperly() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + const int SamplingWindowValue = 3; const int CalculationPeriodValue = 2; @@ -146,10 +152,11 @@ public void ConfigureMonitor_GivenOptionsDelegate_InitializeTrackerWithOptionsPr Assert.Equal(TimeSpan.FromSeconds(CalculationPeriodValue), options!.Value.PublishingWindow); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void ConfigureMonitor_GivenIConfigurationSection_InitializeTrackerWithOptionsProperly() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + const int SamplingWindowValue = 3; const int CalculationPeriod = 2; const int SamplingPeriodValue = 1; @@ -188,10 +195,11 @@ public void ConfigureMonitor_GivenIConfigurationSection_InitializeTrackerWithOpt Assert.Equal(TimeSpan.FromSeconds(CalculationPeriod), options!.Value.PublishingWindow); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void Registering_Resource_Utilization_Adds_Only_One_Object_Of_Type_ResourceUtilizationService_To_DI_Container() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + using var host = FakeHost.CreateBuilder() .ConfigureServices(services => { @@ -212,10 +220,11 @@ public void Registering_Resource_Utilization_Adds_Only_One_Object_Of_Type_Resour Assert.Same(tracker as ResourceMonitorService, background as ResourceMonitorService); } - [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.Windows, SkipReason = "For MacOs only.")] - [ConditionalFact] + [Fact] public void AddResourceMonitoringInternal_WhenMacOs_ReturnsSameServiceCollection() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "For MacOs only."); + var services = new ServiceCollection(); // Act @@ -226,10 +235,11 @@ public void AddResourceMonitoringInternal_WhenMacOs_ReturnsSameServiceCollection Assert.DoesNotContain(services, s => s.ServiceType == typeof(ISnapshotProvider)); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void AddResourceMonitoring_AddsISnapshotProvider() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + var services = new ServiceCollection(); // Act @@ -240,10 +250,11 @@ public void AddResourceMonitoring_AddsISnapshotProvider() Assert.Contains(services, s => s.ServiceType == typeof(ISnapshotProvider)); } - [OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Not supported on MacOs.")] - [ConditionalFact] + [Fact] public void AddResourceMonitoringInternal_CallsConfigureDelegate() { + Assert.SkipUnless(!RuntimeInformation.IsOSPlatform(OSPlatform.OSX), "Not supported on MacOs."); + var services = new ServiceCollection(); bool delegateCalled = false; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoRatePerfCounterTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoRatePerfCounterTests.cs index f2131afd3f5..3c1d1ee50d7 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoRatePerfCounterTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoRatePerfCounterTests.cs @@ -1,23 +1,27 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.InteropServices; using System.Runtime.Versioning; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; using Microsoft.Extensions.Time.Testing; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Disk.Test; [SupportedOSPlatform("windows")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class WindowsDiskIoRatePerfCounterTests { + public WindowsDiskIoRatePerfCounterTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + private const string CategoryName = "LogicalDisk"; - [ConditionalFact] + [Fact] public void DiskReadsPerfCounter_Per60Seconds() { const string CounterName = WindowsDiskPerfCounterNames.DiskReadsCounter; @@ -64,7 +68,7 @@ public void DiskReadsPerfCounter_Per60Seconds() Assert.Equal(660, ratePerfCounters.TotalCountDict["D:"]); // 450 + 3.5 * 60 = 660 } - [ConditionalFact] + [Fact] public void DiskWriteBytesPerfCounter_Per30Seconds() { const string CounterName = WindowsDiskPerfCounterNames.DiskWriteBytesCounter; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoTimePerfCounterTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoTimePerfCounterTests.cs index 4daf808240b..d39b8a6515a 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoTimePerfCounterTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskIoTimePerfCounterTests.cs @@ -2,22 +2,26 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.InteropServices; using System.Runtime.Versioning; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; using Microsoft.Extensions.Time.Testing; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Disk.Test; [SupportedOSPlatform("windows")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class WindowsDiskIoTimePerfCounterTests { + public WindowsDiskIoTimePerfCounterTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + private const string CategoryName = "LogicalDisk"; - [ConditionalFact] + [Fact] public void DiskReadsPerfCounter_Per60Seconds() { const string CounterName = WindowsDiskPerfCounterNames.DiskReadsCounter; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskMetricsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskMetricsTests.cs index a592aacce19..aea99cf7610 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskMetricsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Disk/WindowsDiskMetricsTests.cs @@ -1,10 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Diagnostics.Metrics; using System.Linq; +using System.Runtime.InteropServices; using System.Runtime.Versioning; using Microsoft.Extensions.Diagnostics.Metrics.Testing; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; @@ -12,20 +13,23 @@ using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Disk.Test; [SupportedOSPlatform("windows")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class WindowsDiskMetricsTests { + public WindowsDiskMetricsTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + private const string CategoryName = "LogicalDisk"; private readonly FakeLogger _fakeLogger = new(); - [ConditionalFact] + [Fact] public void Creates_Meter_With_Correct_Name() { using var meterFactory = new TestMeterFactory(); @@ -43,7 +47,7 @@ public void Creates_Meter_With_Correct_Name() Assert.Equal(ResourceUtilizationInstruments.MeterName, meter.Name); } - [ConditionalFact] + [Fact] public void DiskOperationMetricsTest() { using var meterFactory = new TestMeterFactory(); @@ -117,7 +121,7 @@ public void DiskOperationMetricsTest() Assert.Equal(5700, measurements.Last(x => x.MatchesTags(writeTag, deviceTagD)).Value); // 3600 + 35 * 60 = 5700 } - [ConditionalFact] + [Fact] public void DiskIoBytesMetricsTest() { using var meterFactory = new TestMeterFactory(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/MemoryInfoTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/MemoryInfoTests.cs index ea20aad2d65..f8bca7bd500 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/MemoryInfoTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/MemoryInfoTests.cs @@ -1,8 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Interop; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; @@ -12,10 +12,14 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; /// /// These tests are added for coverage reasons, but the code doesn't have /// the necessary environment predictability to really test it. -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public sealed class MemoryInfoTests { - [ConditionalFact] + public MemoryInfoTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + + [Fact] public void GetGlobalMemory() { var memoryStatus = new MemoryInfo().GetMemoryStatus(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterFactoryTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterFactoryTests.cs index 768fd268175..3827563d16d 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterFactoryTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterFactoryTests.cs @@ -1,17 +1,21 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.InteropServices; using System.Runtime.Versioning; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; [SupportedOSPlatform("windows")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class PerformanceCounterFactoryTests { - [ConditionalFact] + public PerformanceCounterFactoryTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + + [Fact] public void GetInstanceNameTest() { var performanceCounterFactory = new PerformanceCounterFactory(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterWrapperTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterWrapperTests.cs index f27646ae327..1ab159bc6bd 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterWrapperTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/PerformanceCounterWrapperTests.cs @@ -1,17 +1,21 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.InteropServices; using System.Runtime.Versioning; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; [SupportedOSPlatform("windows")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class PerformanceCounterWrapperTests { - [ConditionalFact] + public PerformanceCounterWrapperTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + + [Fact] public void GetInstanceNameTest() { var wrapper = new PerformanceCounterWrapper("Processor", "% Processor Time", "_Total"); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/ProcessInfoTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/ProcessInfoTests.cs index ab83f2677df..cda6bb24da8 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/ProcessInfoTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/ProcessInfoTests.cs @@ -1,8 +1,7 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Interop; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; @@ -14,7 +13,7 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; /// the necessary environment predictability to really test it. public sealed class ProcessInfoTests { - [ConditionalFact] + [Fact] public void GetCurrentProcessMemoryUsage() { var workingSet64 = new ProcessInfo().GetCurrentProcessMemoryUsage(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/SystemInfoTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/SystemInfoTests.cs index a0e9485bd00..d006a7c4ea5 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/SystemInfoTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/SystemInfoTests.cs @@ -1,8 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Interop; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; @@ -12,13 +12,17 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; /// /// These tests are added for coverage reasons, but the code doesn't have /// the necessary environment predictability to really test it. -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public sealed class SystemInfoTests { + public SystemInfoTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + /// /// Get basic system info. /// - [ConditionalFact] + [Fact] public void GetSystemInfo() { var sysInfo = new SystemInfo().GetSystemInfo(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Tcp6TableInfoTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Tcp6TableInfoTests.cs index a5dfdb5c170..a1cc1b29a87 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Tcp6TableInfoTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/Tcp6TableInfoTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,7 +6,6 @@ using System.Runtime.InteropServices; using System.Threading; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Network; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; @@ -15,9 +14,13 @@ namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; /// Keep this Test to distinguish different tests for IPv6. /// [Collection("Tcp Connection Tests")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public sealed class Tcp6TableInfoTests { + public Tcp6TableInfoTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + public static readonly TimeSpan DefaultTimeSpan = TimeSpan.FromSeconds(5); public static DateTimeOffset StartTimestamp = DateTimeOffset.UtcNow; public static DateTimeOffset NextTimestamp = StartTimestamp.Add(DefaultTimeSpan); @@ -226,7 +229,7 @@ public static uint FakeGetTcp6TableWithFakeInformation(IntPtr pTcp6Table, ref ui return (uint)NTSTATUS.Success; } - [ConditionalFact] + [Fact] public void Test_Tcp6TableInfo_Get_UnsuccessfulStatus_All_The_Time() { var options = new ResourceMonitoringOptions @@ -243,7 +246,7 @@ public void Test_Tcp6TableInfo_Get_UnsuccessfulStatus_All_The_Time() }); } - [ConditionalFact] + [Fact] public void Test_Tcp6TableInfo_Get_InsufficientBuffer_Then_Get_InvalidParameter() { var options = new ResourceMonitoringOptions @@ -259,7 +262,7 @@ public void Test_Tcp6TableInfo_Get_InsufficientBuffer_Then_Get_InvalidParameter( }); } - [ConditionalFact] + [Fact] public void Test_Tcp6TableInfo_Get_Correct_Information() { StartTimestamp = DateTimeOffset.UtcNow; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/TcpTableInfoTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/TcpTableInfoTests.cs index 8c88fc123dd..36171cab650 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/TcpTableInfoTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/TcpTableInfoTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -6,15 +6,18 @@ using System.Runtime.InteropServices; using System.Threading; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Network; -using Microsoft.TestUtilities; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; [Collection("Tcp Connection Tests")] -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public sealed class TcpTableInfoTests { + public TcpTableInfoTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + public static readonly TimeSpan DefaultTimeSpan = TimeSpan.FromSeconds(5); public static DateTimeOffset StartTimestamp = DateTimeOffset.UtcNow; public static DateTimeOffset NextTimestamp = StartTimestamp.Add(DefaultTimeSpan); @@ -169,7 +172,7 @@ public static unsafe uint FakeGetTcpTableWithFakeInformation(IntPtr pTcpTable, r return (uint)NTSTATUS.Success; } - [ConditionalFact] + [Fact] public void Test_TcpTableInfo_Get_UnsuccessfulStatus_All_The_Time() { var options = new ResourceMonitoringOptions @@ -185,7 +188,7 @@ public void Test_TcpTableInfo_Get_UnsuccessfulStatus_All_The_Time() }); } - [ConditionalFact] + [Fact] public void Test_TcpTableInfo_Get_InsufficientBuffer_Then_Get_InvalidParameter() { var options = new ResourceMonitoringOptions @@ -201,7 +204,7 @@ public void Test_TcpTableInfo_Get_InsufficientBuffer_Then_Get_InvalidParameter() }); } - [ConditionalFact] + [Fact] public void Test_TcpTableInfo_Get_Correct_Information() { StartTimestamp = DateTimeOffset.UtcNow; @@ -262,7 +265,7 @@ public void Test_TcpTableInfo_Get_Correct_Information() Assert.Equal(2, tcpStateInfo.DeleteTcbCount); } - [ConditionalFact] + [Fact] public void Test_TcpTableInfo_CalculateCount_default_branch() { TcpStateInfo tcpStateInfo = new(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsNetworkMetricsTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsNetworkMetricsTests.cs index bafb5816eb9..c2146cbecb4 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsNetworkMetricsTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsNetworkMetricsTests.cs @@ -1,21 +1,25 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.Metrics; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Network; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public class WindowsNetworkMetricsTests { - [ConditionalFact] + public WindowsNetworkMetricsTests() + { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + } + + [Fact] public void Creates_Meter_With_Correct_Name() { using var meterFactory = new TestMeterFactory(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs index 32cf5117aac..a93d515e7bb 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.ResourceMonitoring.Tests/Windows/WindowsSnapshotProviderTests.cs @@ -1,9 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics.Metrics; using System.Linq; +using System.Runtime.InteropServices; using System.Threading.Tasks; using Microsoft.Extensions.Diagnostics.Metrics.Testing; using Microsoft.Extensions.Diagnostics.ResourceMonitoring.Test.Helpers; @@ -12,14 +13,12 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.Time.Testing; using Microsoft.Shared.Instruments; -using Microsoft.TestUtilities; using Moq; using VerifyXunit; using Xunit; namespace Microsoft.Extensions.Diagnostics.ResourceMonitoring.Windows.Test; -[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "Windows specific.")] public sealed class WindowsSnapshotProviderTests { private const string VerifiedDataDirectory = "Verified"; @@ -30,6 +29,8 @@ public sealed class WindowsSnapshotProviderTests public WindowsSnapshotProviderTests() { + Assert.SkipUnless(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "Skipped on Linux/macOS"); + _options = Options.Options.Create(new()); using var meter = new Meter(nameof(BasicConstructor)); _meterFactoryMock = new Mock(); @@ -39,7 +40,7 @@ public WindowsSnapshotProviderTests() _fakeLogger = new FakeLogger(); } - [ConditionalFact] + [Fact] public void BasicConstructor() { var provider = new WindowsSnapshotProvider(_fakeLogger, _meterFactoryMock.Object, _options); @@ -51,7 +52,7 @@ public void BasicConstructor() Assert.Equal(memoryStatus.TotalPhys, provider.Resources.MaximumMemoryInBytes); } - [ConditionalFact] + [Fact] public void GetSnapshot_DoesNotThrowExceptions() { var provider = new WindowsSnapshotProvider(_fakeLogger, _meterFactoryMock.Object, _options); @@ -60,7 +61,7 @@ public void GetSnapshot_DoesNotThrowExceptions() Assert.Null(exception); } - [ConditionalFact] + [Fact] public Task SnapshotProvider_EmitsLogRecord() { var provider = new WindowsSnapshotProvider(_fakeLogger, _meterFactoryMock.Object, _options); @@ -71,7 +72,7 @@ public Task SnapshotProvider_EmitsLogRecord() return Verifier.Verify(logRecords[0]).UseDirectory(VerifiedDataDirectory); } - [ConditionalTheory] + [Theory] [CombinatorialData] public void SnapshotProvider_EmitsCpuMetrics(bool useZeroToOneRange) { @@ -112,7 +113,7 @@ public void SnapshotProvider_EmitsCpuMetrics(bool useZeroToOneRange) Assert.Equal(0.05 * multiplier, metricCollector.LastMeasurement?.Value); // Still consuming 5% of the CPU } - [ConditionalTheory] + [Theory] [CombinatorialData] public void SnapshotProvider_EmitsMemoryMetrics(bool useZeroToOneRange) { @@ -162,7 +163,7 @@ public void SnapshotProvider_EmitsMemoryMetrics(bool useZeroToOneRange) Assert.Equal(1 * multiplier, Math.Round(metricCollector.LastMeasurement.Value)); // Consuming 100% of the memory } - [ConditionalFact] + [Fact] public void Provider_Returns_MemoryConsumption() { // This is a synthetic test to have full test coverage: @@ -170,7 +171,7 @@ public void Provider_Returns_MemoryConsumption() Assert.InRange(usage, 0, long.MaxValue); } - [ConditionalFact] + [Fact] public void Provider_Creates_Meter_With_Correct_Name() { using var meterFactory = new TestMeterFactory(); diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.LogEnumeration.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.LogEnumeration.cs index 9ded05209d5..cf5a748542f 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.LogEnumeration.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.LogEnumeration.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -8,7 +8,6 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Extensions.Logging.Testing.Test.Logging; diff --git a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.cs b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.cs index 63ce2a7e718..4d772bf60af 100644 --- a/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.cs +++ b/test/Libraries/Microsoft.Extensions.Diagnostics.Testing.Tests/Logging/FakeLogCollectorTests.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Globalization; using Microsoft.Extensions.Time.Testing; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Extensions.Logging.Testing.Test.Logging; @@ -13,10 +12,22 @@ public partial class FakeLogCollectorTests { private class Output : ITestOutputHelper { + private readonly System.Text.StringBuilder _sb = new(); + public string Last { get; private set; } = string.Empty; + string ITestOutputHelper.Output => _sb.ToString(); + + public void Write(string message) + { + _sb.Append(message); + Last += message; + } + + public void Write(string format, params object[] args) => Write(string.Format(CultureInfo.InvariantCulture, format, args)); public void WriteLine(string message) { + _sb.AppendLine(message); Last = message; } diff --git a/test/Libraries/Microsoft.Extensions.Hosting.Testing.Tests/FakeHostTests.cs b/test/Libraries/Microsoft.Extensions.Hosting.Testing.Tests/FakeHostTests.cs index f96fb65a7ce..1792b61b0e9 100644 --- a/test/Libraries/Microsoft.Extensions.Hosting.Testing.Tests/FakeHostTests.cs +++ b/test/Libraries/Microsoft.Extensions.Hosting.Testing.Tests/FakeHostTests.cs @@ -33,9 +33,24 @@ public async Task Host_ShutsDownAfterTimeout() }) .StartAsync(); - await Task.Delay(100); // Give some time for the host to shut down + // poll up to 50 times (5 seconds total) until the host has shut down and its service provider has been disposed + ObjectDisposedException? captured = null; + for (var i = 0; i < 50; i++) + { + try + { + host.Services.GetService(); + } + catch (ObjectDisposedException ex) + { + captured = ex; + break; + } - Assert.Throws(() => host.Services.GetService()); + await Task.Delay(100); + } + + Assert.NotNull(captured); } [Fact] @@ -50,7 +65,12 @@ public async Task StartAsync_NoTokenProvided_UsesDefaultTimeout() var sut = new FakeHost(hostMock.Object, new FakeHostOptions { StartUpTimeout = TimeSpan.Zero }); #pragma warning restore CA2000 await sut.StartAsync(); - await Task.Delay(TimeSpan.FromMilliseconds(100)); + + // poll up to 50 times (5 seconds total) until the inner IHost.StartAsync invocation has been recorded + for (var i = 0; i < 50 && hostMock.Invocations.Count == 0; i++) + { + await Task.Delay(100); + } hostMock.VerifyAll(); } diff --git a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Microsoft.Extensions.Http.Diagnostics.Tests.csproj b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Microsoft.Extensions.Http.Diagnostics.Tests.csproj index 4bc20735577..118937eb1ed 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Microsoft.Extensions.Http.Diagnostics.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Http.Diagnostics.Tests/Microsoft.Extensions.Http.Diagnostics.Tests.csproj @@ -27,7 +27,7 @@ - + diff --git a/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Microsoft.Extensions.Http.Resilience.Tests.csproj b/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Microsoft.Extensions.Http.Resilience.Tests.csproj index 95e047fabb3..cee9a69a16c 100644 --- a/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Microsoft.Extensions.Http.Resilience.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Http.Resilience.Tests/Microsoft.Extensions.Http.Resilience.Tests.csproj @@ -24,11 +24,10 @@ - - + diff --git a/test/Libraries/Microsoft.Extensions.Options.ContextualOptions.Tests/Microsoft.Extensions.Options.Contextual.Tests.csproj b/test/Libraries/Microsoft.Extensions.Options.ContextualOptions.Tests/Microsoft.Extensions.Options.Contextual.Tests.csproj index d440b8820db..6709628b4d1 100644 --- a/test/Libraries/Microsoft.Extensions.Options.ContextualOptions.Tests/Microsoft.Extensions.Options.Contextual.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Options.ContextualOptions.Tests/Microsoft.Extensions.Options.Contextual.Tests.csproj @@ -14,7 +14,7 @@ - + diff --git a/test/Libraries/Microsoft.Extensions.Resilience.Tests/Microsoft.Extensions.Resilience.Tests.csproj b/test/Libraries/Microsoft.Extensions.Resilience.Tests/Microsoft.Extensions.Resilience.Tests.csproj index 163b01082d1..c7b2043dcc3 100644 --- a/test/Libraries/Microsoft.Extensions.Resilience.Tests/Microsoft.Extensions.Resilience.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Resilience.Tests/Microsoft.Extensions.Resilience.Tests.csproj @@ -8,11 +8,6 @@ true - - - true - - diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/CancellationTests.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/CancellationTests.cs index 786882afc1d..1e19807c7f4 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/CancellationTests.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/CancellationTests.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Net.Sockets; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/LoopbackDnsTestBase.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/LoopbackDnsTestBase.cs index 6d2aba6cb64..ca3fecddcd8 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/LoopbackDnsTestBase.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/LoopbackDnsTestBase.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Options; using Microsoft.Extensions.ServiceDiscovery.Dns.Tests; using Microsoft.Extensions.Time.Testing; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveAddressesTests.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveAddressesTests.cs index 0a6c97a26c1..cc1940d7d14 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveAddressesTests.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveAddressesTests.cs @@ -3,7 +3,7 @@ using System.Net; using System.Net.Sockets; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveServiceTests.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveServiceTests.cs index 82ca3175789..1ff9c1c8738 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveServiceTests.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/ResolveServiceTests.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Net; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/RetryTests.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/RetryTests.cs index 3d6f3724484..a8017223851 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/RetryTests.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/RetryTests.cs @@ -3,7 +3,7 @@ using System.Net; using System.Net.Sockets; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/TcpFailoverTests.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/TcpFailoverTests.cs index b2891cfb512..a6a4769b7fc 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/TcpFailoverTests.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/Resolver/TcpFailoverTests.cs @@ -3,7 +3,7 @@ using System.Net; using System.Net.Sockets; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Resolver.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/XunitLoggerFactoryExtensions.cs b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/XunitLoggerFactoryExtensions.cs index 6667688f16e..71a4a9907df 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/XunitLoggerFactoryExtensions.cs +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Dns.Tests/XunitLoggerFactoryExtensions.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Extensions.ServiceDiscovery.Dns.Tests; diff --git a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Tests/Microsoft.Extensions.ServiceDiscovery.Tests.csproj b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Tests/Microsoft.Extensions.ServiceDiscovery.Tests.csproj index a589eccc256..4dc289c3caa 100644 --- a/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Tests/Microsoft.Extensions.ServiceDiscovery.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.ServiceDiscovery.Tests/Microsoft.Extensions.ServiceDiscovery.Tests.csproj @@ -8,7 +8,7 @@ $(NoWarn);IDE0004;IDE0040;IDE0055;IDE1006;CA2000;S1121;S1128;SA1316;SA1500;SA1513 - + diff --git a/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Microsoft.Extensions.Telemetry.Abstractions.Tests.csproj b/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Microsoft.Extensions.Telemetry.Abstractions.Tests.csproj index 387cec3c5c0..267e1de7143 100644 --- a/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Microsoft.Extensions.Telemetry.Abstractions.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Telemetry.Abstractions.Tests/Microsoft.Extensions.Telemetry.Abstractions.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Logging/ExtendedLoggerTests.cs b/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Logging/ExtendedLoggerTests.cs index f91cbcabce7..d0e71d3421f 100644 --- a/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Logging/ExtendedLoggerTests.cs +++ b/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Logging/ExtendedLoggerTests.cs @@ -531,7 +531,12 @@ public static void Exceptions(bool includeExceptionMessage) if (includeExceptionMessage) { var exceptionMessage = snap[3].GetStructuredStateValue("exception.message"); +#if NETFRAMEWORK + // On .NET Framework, AggregateException.Message does not include inner exception messages + Assert.Equal("EM4", exceptionMessage); +#else Assert.Equal("EM4 (EM1) (EM2) (EM3)", exceptionMessage); +#endif Assert.Contains("EM1", stackTrace); Assert.Contains("EM2", stackTrace); diff --git a/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Microsoft.Extensions.Telemetry.Tests.csproj b/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Microsoft.Extensions.Telemetry.Tests.csproj index b52f7b92d76..73f6aa0f1de 100644 --- a/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Microsoft.Extensions.Telemetry.Tests.csproj +++ b/test/Libraries/Microsoft.Extensions.Telemetry.Tests/Microsoft.Extensions.Telemetry.Tests.csproj @@ -2,7 +2,7 @@ Microsoft.Extensions.Telemetry Unit tests for Microsoft.Extensions.Telemetry. - $(NoWarn);CS0436 + $(NoWarn);CS0436 diff --git a/test/ProjectTemplates/Infrastructure/DotNetNewCommand.cs b/test/ProjectTemplates/Infrastructure/DotNetNewCommand.cs index e013d0d4e4e..ba0ed105755 100644 --- a/test/ProjectTemplates/Infrastructure/DotNetNewCommand.cs +++ b/test/ProjectTemplates/Infrastructure/DotNetNewCommand.cs @@ -1,9 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Threading.Tasks; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Shared.ProjectTemplates.Tests; diff --git a/test/ProjectTemplates/Infrastructure/MessageSinkTestOutputHelper.cs b/test/ProjectTemplates/Infrastructure/MessageSinkTestOutputHelper.cs index 6118a0ad4e2..17c25cf99f2 100644 --- a/test/ProjectTemplates/Infrastructure/MessageSinkTestOutputHelper.cs +++ b/test/ProjectTemplates/Infrastructure/MessageSinkTestOutputHelper.cs @@ -1,7 +1,8 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Xunit.Abstractions; +using System.Text; +using Xunit; using Xunit.Sdk; namespace Microsoft.Shared.ProjectTemplates.Tests; @@ -9,19 +10,37 @@ namespace Microsoft.Shared.ProjectTemplates.Tests; public sealed class MessageSinkTestOutputHelper : ITestOutputHelper { private readonly IMessageSink _messageSink; + private readonly StringBuilder _sb = new(); public MessageSinkTestOutputHelper(IMessageSink messageSink) { _messageSink = messageSink; } + public string Output => _sb.ToString(); + + public void Write(string message) + { + _sb.Append(message); + _messageSink.OnMessage(new Xunit.v3.DiagnosticMessage(message)); + } + + public void Write(string format, params object[] args) + { + _sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, format, args); + _messageSink.OnMessage(new Xunit.v3.DiagnosticMessage(format, args)); + } + public void WriteLine(string message) { - _messageSink.OnMessage(new DiagnosticMessage(message)); + _sb.AppendLine(message); + _messageSink.OnMessage(new Xunit.v3.DiagnosticMessage(message)); } public void WriteLine(string format, params object[] args) { - _messageSink.OnMessage(new DiagnosticMessage(format, args)); + _sb.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, format, args); + _sb.AppendLine(); + _messageSink.OnMessage(new Xunit.v3.DiagnosticMessage(format, args)); } } diff --git a/test/ProjectTemplates/Infrastructure/TemplateExecutionTestBase.cs b/test/ProjectTemplates/Infrastructure/TemplateExecutionTestBase.cs index 188f5022fd1..14d29102bfe 100644 --- a/test/ProjectTemplates/Infrastructure/TemplateExecutionTestBase.cs +++ b/test/ProjectTemplates/Infrastructure/TemplateExecutionTestBase.cs @@ -1,10 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; +using Xunit.Sdk; namespace Microsoft.Shared.ProjectTemplates.Tests; diff --git a/test/ProjectTemplates/Infrastructure/TemplateExecutionTestClassFixtureBase.cs b/test/ProjectTemplates/Infrastructure/TemplateExecutionTestClassFixtureBase.cs index 4c9939d960a..3ec18cf45be 100644 --- a/test/ProjectTemplates/Infrastructure/TemplateExecutionTestClassFixtureBase.cs +++ b/test/ProjectTemplates/Infrastructure/TemplateExecutionTestClassFixtureBase.cs @@ -1,11 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Threading.Tasks; using Xunit; -using Xunit.Abstractions; +using Xunit.Sdk; namespace Microsoft.Shared.ProjectTemplates.Tests; @@ -43,7 +43,7 @@ protected TemplateExecutionTestClassFixtureBase(TemplateExecutionTestConfigurati _sandboxProjectsPath = Path.Combine(_sandboxOutput, "projects"); } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { // Here, we clear execution test output from the previous test run, if it exists. // It's critical that this clearing happens *before* the tests start, *not* after they complete. @@ -157,9 +157,11 @@ public void SetCurrentTestOutputHelper(ITestOutputHelper? outputHelper) _currentTestOutputHelper = outputHelper; } - public Task DisposeAsync() + public ValueTask DisposeAsync() { + GC.SuppressFinalize(this); + // Only here to implement IAsyncLifetime. Not currently used. - return Task.CompletedTask; + return ValueTask.CompletedTask; } } diff --git a/test/ProjectTemplates/Infrastructure/TestCommand.cs b/test/ProjectTemplates/Infrastructure/TestCommand.cs index dfe89030cad..8cb9fa2a687 100644 --- a/test/ProjectTemplates/Infrastructure/TestCommand.cs +++ b/test/ProjectTemplates/Infrastructure/TestCommand.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; @@ -7,7 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using Xunit.Abstractions; +using Xunit; namespace Microsoft.Shared.ProjectTemplates.Tests; diff --git a/test/ProjectTemplates/Infrastructure/XunitLoggerProvider.cs b/test/ProjectTemplates/Infrastructure/XunitLoggerProvider.cs new file mode 100644 index 00000000000..89325f406db --- /dev/null +++ b/test/ProjectTemplates/Infrastructure/XunitLoggerProvider.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Microsoft.Extensions.Logging; +using Xunit; + +namespace Microsoft.Shared.ProjectTemplates.Tests; + +internal sealed class XunitLoggerProvider : ILoggerProvider +{ + private readonly ITestOutputHelper _output; + + public XunitLoggerProvider(ITestOutputHelper output) + { + _output = output; + } + + public ILogger CreateLogger(string categoryName) => new XunitLogger(_output, categoryName); + + public void Dispose() + { + // Nothing to dispose. + } + + private sealed class XunitLogger : ILogger + { + private readonly ITestOutputHelper _output; + private readonly string _categoryName; + + public XunitLogger(ITestOutputHelper output, string categoryName) + { + _output = output; + _categoryName = categoryName; + } + + public IDisposable? BeginScope(TState state) + where TState : notnull => null; + + public bool IsEnabled(LogLevel logLevel) => true; + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) + { + _output.WriteLine($"[{logLevel}] {_categoryName}: {formatter(state, exception)}"); + + if (exception is not null) + { + _output.WriteLine(exception.ToString()); + } + } + } +} diff --git a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPIExecutionTests.cs b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPIExecutionTests.cs index 675fb642aa6..68674e9016e 100644 --- a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPIExecutionTests.cs +++ b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPIExecutionTests.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using Microsoft.Shared.ProjectTemplates.Tests; using Xunit; -using Xunit.Abstractions; using static Microsoft.Shared.ProjectTemplates.Tests.TemplateTestUtilities; namespace Microsoft.Agents.AI.ProjectTemplates.Tests; diff --git a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPISnapshotTests.cs b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPISnapshotTests.cs index a93915e3252..8285ab383d7 100644 --- a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPISnapshotTests.cs +++ b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/AIAgentWebAPISnapshotTests.cs @@ -5,9 +5,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Shared.ProjectTemplates.Tests; using Microsoft.TemplateEngine.Authoring.TemplateVerifier; -using Microsoft.TemplateEngine.TestHelper; using Xunit; -using Xunit.Abstractions; using static Microsoft.Shared.ProjectTemplates.Tests.TemplateTestUtilities; namespace Microsoft.Agents.AI.ProjectTemplates.Tests; diff --git a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/Microsoft.Agents.AI.ProjectTemplates.Tests.csproj b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/Microsoft.Agents.AI.ProjectTemplates.Tests.csproj index df94c9d0841..25dab0a6420 100644 --- a/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/Microsoft.Agents.AI.ProjectTemplates.Tests.csproj +++ b/test/ProjectTemplates/Microsoft.Agents.AI.ProjectTemplates.IntegrationTests/Microsoft.Agents.AI.ProjectTemplates.Tests.csproj @@ -11,8 +11,7 @@ - - + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebExecutionTests.cs b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebExecutionTests.cs index 513f4cf0394..74bfd3ffdd6 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebExecutionTests.cs +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebExecutionTests.cs @@ -1,12 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Shared.ProjectTemplates.Tests; -using Microsoft.TestUtilities; using Xunit; -using Xunit.Abstractions; using static Microsoft.Shared.ProjectTemplates.Tests.TemplateTestUtilities; namespace Microsoft.Extensions.AI.Templates.Tests; @@ -105,8 +103,7 @@ public async Task CreateRestoreAndBuild_AspireProjectName() /// Set the environment variable AI_TEMPLATES_TEST_PROJECT_NAMES to "true" or "1" /// to enable it. /// - [ConditionalTheory] - [EnvironmentVariableCondition("AI_TEMPLATES_TEST_PROJECT_NAMES", "true", "1")] + [Theory] [InlineData("dot.name")] [InlineData("project.123")] [InlineData("space name")] @@ -117,6 +114,11 @@ public async Task CreateRestoreAndBuild_AspireProjectName() [InlineData("nomatch")] public async Task CreateRestoreAndBuild_AspireProjectName_Variants(string projectName) { + string? envValue = System.Environment.GetEnvironmentVariable("AI_TEMPLATES_TEST_PROJECT_NAMES"); + Assert.SkipUnless( + string.Equals(envValue, "true", System.StringComparison.OrdinalIgnoreCase) || envValue == "1", + "Set the environment variable AI_TEMPLATES_TEST_PROJECT_NAMES to 'true' or '1' to enable this test."); + await CreateRestoreAndBuild(projectName, ["--aspire", "--provider", "azureopenai"]); } } diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebSnapshotTests.cs b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebSnapshotTests.cs index dbe71cdbdef..ac02c466ea8 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebSnapshotTests.cs +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/AIChatWebSnapshotTests.cs @@ -1,13 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Shared.ProjectTemplates.Tests; using Microsoft.TemplateEngine.Authoring.TemplateVerifier; -using Microsoft.TemplateEngine.TestHelper; using Xunit; -using Xunit.Abstractions; using static Microsoft.Shared.ProjectTemplates.Tests.TemplateTestUtilities; namespace Microsoft.Extensions.AI.Templates.Tests; diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Microsoft.Extensions.AI.Templates.Tests.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Microsoft.Extensions.AI.Templates.Tests.csproj index da35b77fca9..a34edeaa08f 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Microsoft.Extensions.AI.Templates.Tests.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Microsoft.Extensions.AI.Templates.Tests.csproj @@ -1,4 +1,4 @@ - + Tests for Microsoft.Extensions.AI.Templates. @@ -11,18 +11,13 @@ - - + - - - - diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj index c9340b988a1..4378bd51b44 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj @@ -12,6 +12,7 @@ + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj index ebe90e63c31..5c67c9650c0 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj @@ -16,7 +16,8 @@ - + + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj index a7fda7e47f6..8d775d8fb10 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj @@ -12,6 +12,7 @@ + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj index 6ddb23e8847..67b6e6078ea 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.A_aoai_aais.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb._defaults.verified/aichatweb/aichatweb.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb._defaults.verified/aichatweb/aichatweb.csproj index 32d3733d56b..4359829d8ad 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb._defaults.verified/aichatweb/aichatweb.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb._defaults.verified/aichatweb/aichatweb.csproj @@ -15,7 +15,8 @@ - + + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj index d65dd7ef340..4cfed977723 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.AppHost/aichatweb.AppHost.csproj @@ -12,6 +12,7 @@ + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj index 3fc87d336c7..b7c5a4d7be7 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.o_q.verified/aichatweb/aichatweb.Web/aichatweb.Web.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.oai_aais.verified/aichatweb/aichatweb.csproj b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.oai_aais.verified/aichatweb/aichatweb.csproj index 29733223cdf..5efb472f3d6 100644 --- a/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.oai_aais.verified/aichatweb/aichatweb.csproj +++ b/test/ProjectTemplates/Microsoft.Extensions.AI.Templates.IntegrationTests/Snapshots/aichatweb/aichatweb.oai_aais.verified/aichatweb/aichatweb.csproj @@ -17,7 +17,7 @@ - + diff --git a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerExecutionTests.cs b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerExecutionTests.cs index 48aaee30a1c..345a3a27181 100644 --- a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerExecutionTests.cs +++ b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerExecutionTests.cs @@ -1,11 +1,10 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Shared.ProjectTemplates.Tests; using Xunit; -using Xunit.Abstractions; using static Microsoft.Shared.ProjectTemplates.Tests.TemplateTestUtilities; namespace Microsoft.Extensions.AI.Templates.Tests; diff --git a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerSnapshotTests.cs b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerSnapshotTests.cs index 60e38c0f504..33ca4660746 100644 --- a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerSnapshotTests.cs +++ b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/McpServerSnapshotTests.cs @@ -1,13 +1,11 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Shared.ProjectTemplates.Tests; using Microsoft.TemplateEngine.Authoring.TemplateVerifier; -using Microsoft.TemplateEngine.TestHelper; using Xunit; -using Xunit.Abstractions; namespace Microsoft.Extensions.AI.Templates.Tests; diff --git a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/Microsoft.McpServer.ProjectTemplates.Tests.csproj b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/Microsoft.McpServer.ProjectTemplates.Tests.csproj index 7548fbfe084..b144fd407f9 100644 --- a/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/Microsoft.McpServer.ProjectTemplates.Tests.csproj +++ b/test/ProjectTemplates/Microsoft.McpServer.ProjectTemplates.IntegrationTests/Microsoft.McpServer.ProjectTemplates.Tests.csproj @@ -11,8 +11,7 @@ - - + diff --git a/test/Shared/Shared.Tests.csproj b/test/Shared/Shared.Tests.csproj index 2764d5f5d5d..2b55bc6cb1f 100644 --- a/test/Shared/Shared.Tests.csproj +++ b/test/Shared/Shared.Tests.csproj @@ -7,7 +7,7 @@ $(NoWarn);CA1716;S104 $(TestNetCoreTargetFrameworks) - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) + $(TestNetCoreTargetFrameworks)$(ConditionalNet472) diff --git a/test/Shared/Throw/DoubleTests.cs b/test/Shared/Throw/DoubleTests.cs index 72e33cfaf78..1de7b84bc56 100644 --- a/test/Shared/Throw/DoubleTests.cs +++ b/test/Shared/Throw/DoubleTests.cs @@ -136,8 +136,10 @@ public void Shorter_Version_Of_GreaterThan_For_Double_Get_Correct_Argument_Name( const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -147,8 +149,10 @@ public void Shorter_Version_Of_GreaterThanOrEqual_For_Double_Get_Correct_Argumen const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -158,8 +162,10 @@ public void Shorter_Version_Of_LessThan_For_Double_Get_Correct_Argument_Name() const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -169,8 +175,10 @@ public void Shorter_Version_Of_LessThanOrEqual_For_Double_Get_Correct_Argument_N const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -180,8 +188,10 @@ public void Shorter_Version_Of_Zero_For_Double_Get_Correct_Argument_Name() const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -191,8 +201,10 @@ public void Shorter_Version_Of_OutOfRange_For_Double_Get_Correct_Argument_Name() const double Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } diff --git a/test/Shared/Throw/IntegerTests.cs b/test/Shared/Throw/IntegerTests.cs index 206d5b39e66..bdec9fd5517 100644 --- a/test/Shared/Throw/IntegerTests.cs +++ b/test/Shared/Throw/IntegerTests.cs @@ -108,8 +108,10 @@ public void Shorter_Version_Of_GreaterThan_For_Int_Get_Correct_Argument_Name() const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -119,8 +121,10 @@ public void Shorter_Version_Of_GreaterThanOrEqual_For_Int_Get_Correct_Argument_N const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -130,8 +134,10 @@ public void Shorter_Version_Of_LessThan_For_Int_Get_Correct_Argument_Name() const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -141,8 +147,10 @@ public void Shorter_Version_Of_LessThanOrEqual_For_Int_Get_Correct_Argument_Name const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -152,8 +160,10 @@ public void Shorter_Version_Of_Zero_For_Int_Get_Correct_Argument_Name() const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -163,8 +173,10 @@ public void Shorter_Version_Of_OutOfRange_For_Int_Get_Correct_Argument_Name() const int Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -268,8 +280,10 @@ public void Shorter_Version_Of_GreaterThan_For_UInt_Get_Correct_Argument_Name() const uint One = 1; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(One, 0U)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(One, 0U, nameof(One))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -279,8 +293,10 @@ public void Shorter_Version_Of_GreaterThanOrEqual_For_UInt_Get_Correct_Argument_ const uint One = 1; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(One, 0U)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(One, 0U, nameof(One))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -290,8 +306,10 @@ public void Shorter_Version_Of_LessThan_For_UInt_Get_Correct_Argument_Name() const uint Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1U)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1U, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -301,8 +319,10 @@ public void Shorter_Version_Of_LessThanOrEqual_For_UInt_Get_Correct_Argument_Nam const uint Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1U)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1U, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -312,8 +332,10 @@ public void Shorter_Version_Of_Zero_For_UInt_Get_Correct_Argument_Name() const uint Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -323,8 +345,10 @@ public void Shorter_Version_Of_OutOfRange_For_UInt_Get_Correct_Argument_Name() const uint Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1U, 2U)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1U, 2U, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } diff --git a/test/Shared/Throw/LongTests.cs b/test/Shared/Throw/LongTests.cs index 553dc0ba43f..ecf51131754 100644 --- a/test/Shared/Throw/LongTests.cs +++ b/test/Shared/Throw/LongTests.cs @@ -108,8 +108,10 @@ public void Shorter_Version_Of_GreaterThan_For_Long_Get_Correct_Argument_Name() const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -119,8 +121,10 @@ public void Shorter_Version_Of_GreaterThanOrEqual_For_Long_Get_Correct_Argument_ const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(Zero, -1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -130,8 +134,10 @@ public void Shorter_Version_Of_LessThan_For_Long_Get_Correct_Argument_Name() const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -141,8 +147,10 @@ public void Shorter_Version_Of_LessThanOrEqual_For_Long_Get_Correct_Argument_Nam const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -152,8 +160,10 @@ public void Shorter_Version_Of_Zero_For_Long_Get_Correct_Argument_Name() const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -163,8 +173,10 @@ public void Shorter_Version_Of_OutOfRange_For_Long_Get_Correct_Argument_Name() const long Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1, 2, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -268,8 +280,10 @@ public void Shorter_Version_Of_GreaterThan_For_ULong_Get_Correct_Argument_Name() const ulong One = 1; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(One, 0UL)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThan(One, 0UL, nameof(One))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -279,8 +293,10 @@ public void Shorter_Version_Of_GreaterThanOrEqual_For_ULong_Get_Correct_Argument const ulong One = 1; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(One, 0UL)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfGreaterThanOrEqual(One, 0UL, nameof(One))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -290,8 +306,10 @@ public void Shorter_Version_Of_LessThan_For_ULong_Get_Correct_Argument_Name() const ulong Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1UL)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThan(Zero, 1UL, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -301,8 +319,10 @@ public void Shorter_Version_Of_LessThanOrEqual_For_ULong_Get_Correct_Argument_Na const ulong Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1UL)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfLessThanOrEqual(Zero, 1UL, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -312,8 +332,10 @@ public void Shorter_Version_Of_Zero_For_ULong_Get_Correct_Argument_Name() const ulong Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfZero(Zero, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -323,8 +345,10 @@ public void Shorter_Version_Of_OutOfRange_For_ULong_Get_Correct_Argument_Name() const ulong Zero = 0; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1UL, 2UL)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange(Zero, 1UL, 2UL, nameof(Zero))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } diff --git a/test/Shared/Throw/ThrowTest.cs b/test/Shared/Throw/ThrowTest.cs index 691217d86ce..15c5da0c379 100644 --- a/test/Shared/Throw/ThrowTest.cs +++ b/test/Shared/Throw/ThrowTest.cs @@ -144,8 +144,10 @@ public void Shorter_Version_Of_Throws_Get_Correct_Argument_Name() Random? somethingThatIsNull = null; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNull(somethingThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfNull(somethingThatIsNull, nameof(somethingThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -157,9 +159,11 @@ public void Shorter_Version_Of_Throws_Get_Correct_Argument_Name_For_Object_Check object somethingThatIsNotNull = new(); var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNullOrMemberNull(somethingThatIsNull, somethingNestedThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception( () => Throw.IfNullOrMemberNull(somethingThatIsNull, somethingNestedThatIsNull, nameof(somethingThatIsNull), nameof(somethingNestedThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -171,9 +175,11 @@ public void Shorter_Version_Of_Throws_Get_Correct_Argument_Name_For_Member_Check object somethingThatIsNotNull = new(); var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNullOrMemberNull(red, somethingNestedThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception( () => Throw.IfNullOrMemberNull(red, somethingNestedThatIsNull, nameof(red), nameof(somethingNestedThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); var expectedMessage = $"Member {nameof(somethingNestedThatIsNull)} of {nameof(red)} is null"; @@ -185,9 +191,11 @@ public void Shorter_Version_Of_Throws_Get_Correct_Argument_Name_For_Member_Check Assert.Equal(expectedMessage, exceptionImplicitArgumentName.Message); exceptionImplicitArgumentName = Record.Exception(() => Throw.IfMemberNull(somethingThatIsNotNull, somethingNestedThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); exceptionExplicitArgumentName = Record.Exception( () => Throw.IfMemberNull(somethingThatIsNotNull, somethingNestedThatIsNull, nameof(somethingThatIsNotNull), nameof(somethingNestedThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); expectedMessage = $"Member {nameof(somethingNestedThatIsNull)} of {nameof(somethingThatIsNotNull)} is null"; @@ -268,8 +276,10 @@ public void Shorter_Version_Of_ThrowIfNullOrWhitespace_Get_Correct_Argument_Name string? somethingThatIsNull = null; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNullOrWhitespace(somethingThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfNullOrWhitespace(somethingThatIsNull, nameof(somethingThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -279,8 +289,10 @@ public void Shorter_Version_Of_ThrowIfNullOrEmpty_Get_Correct_Argument_Name() string? somethingThatIsNull = null; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNullOrEmpty(somethingThatIsNull)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfNullOrEmpty(somethingThatIsNull, nameof(somethingThatIsNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } @@ -379,6 +391,7 @@ public void Shorter_Version_Of_NullOrEmpty_Get_Correct_Argument_Name() var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfNullOrEmpty(listButActuallyNull!)); + Assert.NotNull(exceptionImplicitArgumentName); Assert.Contains(nameof(listButActuallyNull), exceptionImplicitArgumentName.Message); } @@ -415,8 +428,10 @@ public void Shorter_Version_Of_OutOfRange_Get_Correct_Argument_Name() Color? colorButNull = null; var exceptionImplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange((Color)colorButNull!)); + Assert.NotNull(exceptionImplicitArgumentName); var exceptionExplicitArgumentName = Record.Exception(() => Throw.IfOutOfRange((Color)colorButNull!, nameof(colorButNull))); + Assert.NotNull(exceptionExplicitArgumentName); Assert.Equal(exceptionExplicitArgumentName.Message, exceptionImplicitArgumentName.Message); } diff --git a/test/TestUtilities/TestUtilities.csproj b/test/TestUtilities/TestUtilities.csproj deleted file mode 100644 index d9e307f1e6d..00000000000 --- a/test/TestUtilities/TestUtilities.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - Microsoft.TestUtilities - Microsoft.TestUtilities - $(TestNetCoreTargetFrameworks)$(ConditionalNet462) - - - - - - - - diff --git a/test/TestUtilities/XUnit/ConditionalFactAttribute.cs b/test/TestUtilities/XUnit/ConditionalFactAttribute.cs deleted file mode 100644 index 92077e27dbc..00000000000 --- a/test/TestUtilities/XUnit/ConditionalFactAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; -using Xunit; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -[XunitTestCaseDiscoverer("Microsoft.TestUtilities." + nameof(ConditionalFactDiscoverer), "Microsoft.TestUtilities")] -public class ConditionalFactAttribute : FactAttribute -{ -} diff --git a/test/TestUtilities/XUnit/ConditionalFactDiscoverer.cs b/test/TestUtilities/XUnit/ConditionalFactDiscoverer.cs deleted file mode 100644 index e007d95860a..00000000000 --- a/test/TestUtilities/XUnit/ConditionalFactDiscoverer.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using Xunit.Abstractions; -using Xunit.Sdk; - -// Do not change this namespace without changing the usage in ConditionalFactAttribute -namespace Microsoft.TestUtilities; - -internal sealed class ConditionalFactDiscoverer : FactDiscoverer -{ - private readonly IMessageSink _diagnosticMessageSink; - - public ConditionalFactDiscoverer(IMessageSink diagnosticMessageSink) - : base(diagnosticMessageSink) - { - _diagnosticMessageSink = diagnosticMessageSink; - } - - protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute) - { - var skipReason = testMethod.EvaluateSkipConditions(); - return skipReason != null - ? new SkippedTestCase(skipReason, _diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) - : new SkippedFactTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), - discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod); // Test case skippable at runtime. - } -} diff --git a/test/TestUtilities/XUnit/ConditionalTheoryAttribute.cs b/test/TestUtilities/XUnit/ConditionalTheoryAttribute.cs deleted file mode 100644 index d5f23068dd0..00000000000 --- a/test/TestUtilities/XUnit/ConditionalTheoryAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; -using Xunit; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] -[XunitTestCaseDiscoverer("Microsoft.TestUtilities." + nameof(ConditionalTheoryDiscoverer), "Microsoft.TestUtilities")] -public class ConditionalTheoryAttribute : TheoryAttribute -{ -} diff --git a/test/TestUtilities/XUnit/ConditionalTheoryDiscoverer.cs b/test/TestUtilities/XUnit/ConditionalTheoryDiscoverer.cs deleted file mode 100644 index e30b5206c8c..00000000000 --- a/test/TestUtilities/XUnit/ConditionalTheoryDiscoverer.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System.Collections.Generic; -using Xunit.Abstractions; -using Xunit.Sdk; - -// Do not change this namespace without changing the usage in ConditionalTheoryAttribute -namespace Microsoft.TestUtilities; - -internal sealed class ConditionalTheoryDiscoverer : TheoryDiscoverer -{ - public ConditionalTheoryDiscoverer(IMessageSink diagnosticMessageSink) - : base(diagnosticMessageSink) - { - } - - private sealed class OptionsWithPreEnumerationEnabled : ITestFrameworkDiscoveryOptions - { - private const string PreEnumerateTheories = "xunit.discovery.PreEnumerateTheories"; - - private readonly ITestFrameworkDiscoveryOptions _original; - - public OptionsWithPreEnumerationEnabled(ITestFrameworkDiscoveryOptions original) - { - _original = original; - } - - public TValue GetValue(string name) - => (name == PreEnumerateTheories) ? (TValue)(object)true : _original.GetValue(name); - - public void SetValue(string name, TValue value) - => _original.SetValue(name, value); - } - - public override IEnumerable Discover(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute) - => base.Discover(new OptionsWithPreEnumerationEnabled(discoveryOptions), testMethod, theoryAttribute); - - protected override IEnumerable CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute) - { - var skipReason = testMethod.EvaluateSkipConditions(); - return skipReason != null - ? new[] { new SkippedTestCase(skipReason, DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod) } - : base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute); - } - - protected override IEnumerable CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[]? dataRow) - { - var skipReason = testMethod.EvaluateSkipConditions(); - if (skipReason == null && dataRow?.Length > 0) - { - var obj = dataRow[0]; - if (obj != null) - { - var type = obj.GetType(); - var property = type.GetProperty("Skip"); - if (property != null && property.PropertyType.Equals(typeof(string))) - { - skipReason = property.GetValue(obj) as string; - } - } - } - - if (skipReason != null) - { - return base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason); - } - - // Create test cases that can handle runtime SkipTestException - return new[] - { - new SkippedTheoryTestCase( - DiagnosticMessageSink, - discoveryOptions.MethodDisplayOrDefault(), - discoveryOptions.MethodDisplayOptionsOrDefault(), - testMethod, - dataRow) - }; - } - - protected override IEnumerable CreateTestCasesForSkippedDataRow( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, - IAttributeInfo theoryAttribute, - object[] dataRow, - string skipReason) - { - return new[] - { - new WORKAROUND_SkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow), - }; - } -} diff --git a/test/TestUtilities/XUnit/EnvironmentVariableConditionAttribute.cs b/test/TestUtilities/XUnit/EnvironmentVariableConditionAttribute.cs deleted file mode 100644 index 45a54409047..00000000000 --- a/test/TestUtilities/XUnit/EnvironmentVariableConditionAttribute.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Linq; - -namespace Microsoft.TestUtilities; - -/// -/// Skips a test based on the value of an environment variable. -/// -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] -public class EnvironmentVariableConditionAttribute : Attribute, ITestCondition -{ - private string? _currentValue; - - /// - /// Initializes a new instance of the class. - /// - /// Name of the environment variable. - /// Value(s) of the environment variable to match for the condition. - /// - /// By default, the test will be run if the value of the variable matches any of the supplied values. - /// Set to False to run the test only if the value does not match. - /// - public EnvironmentVariableConditionAttribute(string variableName, params string[] values) - { - if (string.IsNullOrEmpty(variableName)) - { - throw new ArgumentException("Value cannot be null or empty.", nameof(variableName)); - } - - if (values == null || values.Length == 0) - { - throw new ArgumentException("You must supply at least one value to match.", nameof(values)); - } - - VariableName = variableName; - Values = values; - } - - /// - /// Gets or sets a value indicating whether the test should run if the value of the variable matches any - /// of the supplied values. If False, the test runs only if the value does not match any of the - /// supplied values. Default is True. - /// - public bool RunOnMatch { get; set; } = true; - - /// - /// Gets the name of the environment variable. - /// - public string VariableName { get; } - - /// - /// Gets the value(s) of the environment variable to match for the condition. - /// - public string[] Values { get; } - - /// - /// Gets a value indicating whether the condition is met for the configured environment variable and values. - /// - public bool IsMet - { - get - { - _currentValue ??= Environment.GetEnvironmentVariable(VariableName); - var hasMatched = Values.Any(value => string.Equals(value, _currentValue, StringComparison.OrdinalIgnoreCase)); - - return RunOnMatch ? hasMatched : !hasMatched; - } - } - - /// - /// Gets a value indicating the reason the test was skipped. - /// - public string SkipReason - { - get - { - var value = _currentValue ?? "(null)"; - - return $"Test skipped on environment variable with name '{VariableName}' and value '{value}' " + - $"for the '{nameof(RunOnMatch)}' value of '{RunOnMatch}'."; - } - } -} diff --git a/test/TestUtilities/XUnit/ITestCondition.cs b/test/TestUtilities/XUnit/ITestCondition.cs deleted file mode 100644 index 347f3c69007..00000000000 --- a/test/TestUtilities/XUnit/ITestCondition.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -namespace Microsoft.TestUtilities; - -public interface ITestCondition -{ - bool IsMet { get; } - - string SkipReason { get; } -} diff --git a/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs b/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs deleted file mode 100644 index 586b53d3fcb..00000000000 --- a/test/TestUtilities/XUnit/OSSkipConditionAttribute.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; -#if NETCOREAPP || NET471_OR_GREATER -using System.Runtime.InteropServices; -#endif - -namespace Microsoft.TestUtilities; - -#pragma warning disable CA1019 // Define accessors for attribute arguments -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] -public class OSSkipConditionAttribute : Attribute, ITestCondition -{ - private readonly OperatingSystems _excludedOperatingSystem; - private readonly OperatingSystems _osPlatform; - - public OSSkipConditionAttribute(OperatingSystems operatingSystem) - : this(operatingSystem, GetCurrentOS()) - { - } - - // to enable unit testing - internal OSSkipConditionAttribute(OperatingSystems operatingSystem, OperatingSystems osPlatform) - { - _excludedOperatingSystem = operatingSystem; - _osPlatform = osPlatform; - } - - public bool IsMet - { - get - { - var skip = (_excludedOperatingSystem & _osPlatform) == _osPlatform; - - // Since a test would be executed only if 'IsMet' is true, return false if we want to skip - return !skip; - } - } - - public string SkipReason { get; set; } = "Test cannot run on this operating system."; - - private static OperatingSystems GetCurrentOS() - { -#if NETCOREAPP || NET471_OR_GREATER - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return OperatingSystems.Windows; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - return OperatingSystems.Linux; - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return OperatingSystems.MacOSX; - } - - throw new PlatformNotSupportedException(); -#else - // RuntimeInformation API is only available in .NET Framework 4.7.1+ - // .NET Framework 4.7 and below can only run on Windows. - return OperatingSystems.Windows; -#endif - } -} -#pragma warning restore CA1019 // Define accessors for attribute arguments diff --git a/test/TestUtilities/XUnit/OperatingSystems.cs b/test/TestUtilities/XUnit/OperatingSystems.cs deleted file mode 100644 index 3bee3bac969..00000000000 --- a/test/TestUtilities/XUnit/OperatingSystems.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; - -namespace Microsoft.TestUtilities; - -[Flags] -public enum OperatingSystems -{ - Linux = 1, - MacOSX = 2, - Windows = 4, -} diff --git a/test/TestUtilities/XUnit/SkipTestException.cs b/test/TestUtilities/XUnit/SkipTestException.cs deleted file mode 100644 index 70f7d53c7d8..00000000000 --- a/test/TestUtilities/XUnit/SkipTestException.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; - -namespace Microsoft.TestUtilities; - -public class SkipTestException : Exception -{ - public SkipTestException(string reason) - : base(reason) - { - } -} diff --git a/test/TestUtilities/XUnit/SkippedFactTestCase.cs b/test/TestUtilities/XUnit/SkippedFactTestCase.cs deleted file mode 100644 index 79ace15ea6e..00000000000 --- a/test/TestUtilities/XUnit/SkippedFactTestCase.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -public class SkippedFactTestCase : XunitTestCase -{ - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes", error: true)] - public SkippedFactTestCase() - { - } - - public SkippedFactTestCase( - IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod, object[]? testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - } - - public override async Task RunAsync(IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - { - using SkippedTestMessageBus skipMessageBus = new(messageBus); - var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource); - if (skipMessageBus.SkippedTestCount > 0) - { - result.Failed -= skipMessageBus.SkippedTestCount; - result.Skipped += skipMessageBus.SkippedTestCount; - } - - return result; - } -} diff --git a/test/TestUtilities/XUnit/SkippedTestCase.cs b/test/TestUtilities/XUnit/SkippedTestCase.cs deleted file mode 100644 index 7b59125ffb8..00000000000 --- a/test/TestUtilities/XUnit/SkippedTestCase.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -#nullable disable - -using System; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -public class SkippedTestCase : XunitTestCase -{ - private string _skipReason; - - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public SkippedTestCase() - { - } - - public SkippedTestCase( - string skipReason, - IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod, - object[] testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - _skipReason = skipReason; - } - - protected override string GetSkipReason(IAttributeInfo factAttribute) - => _skipReason ?? base.GetSkipReason(factAttribute); - - public override void Deserialize(IXunitSerializationInfo data) - { - _skipReason = data.GetValue(nameof(_skipReason)); - - // We need to call base after reading our value, because Deserialize will call - // into GetSkipReason. - base.Deserialize(data); - } - - public override void Serialize(IXunitSerializationInfo data) - { - base.Serialize(data); - data.AddValue(nameof(_skipReason), _skipReason); - } -} diff --git a/test/TestUtilities/XUnit/SkippedTestMessageBus.cs b/test/TestUtilities/XUnit/SkippedTestMessageBus.cs deleted file mode 100644 index 230586852b8..00000000000 --- a/test/TestUtilities/XUnit/SkippedTestMessageBus.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Linq; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -/// Implements message bus to communicate tests skipped via SkipTestException. -public sealed class SkippedTestMessageBus : IMessageBus -{ - private readonly IMessageBus _innerBus; - - public SkippedTestMessageBus(IMessageBus innerBus) - { - _innerBus = innerBus; - } - - public int SkippedTestCount { get; private set; } - - public void Dispose() - { - // nothing to dispose - } - - public bool QueueMessage(IMessageSinkMessage message) - { - var testFailed = message as ITestFailed; - - if (testFailed != null) - { - var exceptionType = testFailed.ExceptionTypes.FirstOrDefault(); - if (exceptionType == typeof(SkipTestException).FullName) - { - SkippedTestCount++; - return _innerBus.QueueMessage(new TestSkipped(testFailed.Test, testFailed.Messages.FirstOrDefault())); - } - } - - // Nothing we care about, send it on its way - return _innerBus.QueueMessage(message); - } -} diff --git a/test/TestUtilities/XUnit/SkippedTheoryTestCase.cs b/test/TestUtilities/XUnit/SkippedTheoryTestCase.cs deleted file mode 100644 index e91a8f762d5..00000000000 --- a/test/TestUtilities/XUnit/SkippedTheoryTestCase.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Threading; -using System.Threading.Tasks; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -/// -/// A test case for ConditionalTheory that can handle runtime SkipTestException -/// by wrapping the message bus with SkippedTestMessageBus. -/// -public class SkippedTheoryTestCase : XunitTestCase -{ - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes", error: true)] - public SkippedTheoryTestCase() - { - } - - public SkippedTheoryTestCase( - IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod, - object[]? testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - } - - public override async Task RunAsync(IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cancellationTokenSource) - { - using SkippedTestMessageBus skipMessageBus = new(messageBus); - var result = await base.RunAsync(diagnosticMessageSink, skipMessageBus, constructorArguments, aggregator, cancellationTokenSource); - if (skipMessageBus.SkippedTestCount > 0) - { - result.Failed -= skipMessageBus.SkippedTestCount; - result.Skipped += skipMessageBus.SkippedTestCount; - } - - return result; - } -} \ No newline at end of file diff --git a/test/TestUtilities/XUnit/TestMethodExtensions.cs b/test/TestUtilities/XUnit/TestMethodExtensions.cs deleted file mode 100644 index 88356330daf..00000000000 --- a/test/TestUtilities/XUnit/TestMethodExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System.Linq; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -public static class TestMethodExtensions -{ - public static string? EvaluateSkipConditions(this ITestMethod testMethod) - { - var testClass = testMethod.TestClass.Class; - var assembly = testMethod.TestClass.TestCollection.TestAssembly.Assembly; - var conditionAttributes = testMethod.Method - .GetCustomAttributes(typeof(ITestCondition)) - .Concat(testClass.GetCustomAttributes(typeof(ITestCondition))) - .Concat(assembly.GetCustomAttributes(typeof(ITestCondition))) - .OfType() - .Select(attributeInfo => attributeInfo.Attribute); - - foreach (ITestCondition condition in conditionAttributes.OfType()) - { - if (!condition.IsMet) - { - return condition.SkipReason; - } - } - - return null; - } -} diff --git a/test/TestUtilities/XUnit/WORKAROUND_SkippedDataRowTestCase.cs b/test/TestUtilities/XUnit/WORKAROUND_SkippedDataRowTestCase.cs deleted file mode 100644 index 123dba2fa48..00000000000 --- a/test/TestUtilities/XUnit/WORKAROUND_SkippedDataRowTestCase.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// Borrowed from https://github.com/dotnet/aspnetcore/blob/95ed45c67/src/Testing/src/xunit/ - -using System; -using System.ComponentModel; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Microsoft.TestUtilities; - -// This is a workaround for https://github.com/xunit/xunit/issues/1782 - as such, this code is a copy-paste -// from xUnit with the exception of fixing the bug. -// -// This will only work with [ConditionalTheory]. -internal sealed class WORKAROUND_SkippedDataRowTestCase : XunitTestCase -{ - private string? _skipReason; - - /// - [EditorBrowsable(EditorBrowsableState.Never)] - [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] - public WORKAROUND_SkippedDataRowTestCase() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message sink used to send diagnostic messages. - /// Default method display to use (when not customized). - /// The test method this test case belongs to. - /// The reason that this test case will be skipped. - /// The arguments for the test method. - [Obsolete("Please call the constructor which takes TestMethodDisplayOptions")] - public WORKAROUND_SkippedDataRowTestCase(IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - ITestMethod testMethod, - string skipReason, - object[]? testMethodArguments = null) - : this(diagnosticMessageSink, defaultMethodDisplay, TestMethodDisplayOptions.None, testMethod, skipReason, testMethodArguments) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message sink used to send diagnostic messages. - /// Default method display to use (when not customized). - /// Default method display options to use (when not customized). - /// The test method this test case belongs to. - /// The reason that this test case will be skipped. - /// The arguments for the test method. - public WORKAROUND_SkippedDataRowTestCase(IMessageSink diagnosticMessageSink, - TestMethodDisplay defaultMethodDisplay, - TestMethodDisplayOptions defaultMethodDisplayOptions, - ITestMethod testMethod, - string skipReason, - object[]? testMethodArguments = null) - : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) - { - _skipReason = skipReason; - } - - /// - public override void Deserialize(IXunitSerializationInfo data) - { - // SkipReason has to be read before we call base.Deserialize, this is the workaround. - _skipReason = data.GetValue("SkipReason"); - - base.Deserialize(data); - } - - /// - protected override string? GetSkipReason(IAttributeInfo factAttribute) - { - return _skipReason; - } - - /// - public override void Serialize(IXunitSerializationInfo data) - { - base.Serialize(data); - - data.AddValue("SkipReason", _skipReason); - } -}