Skip to content

Commit 40de799

Browse files
committed
feat: Add .NET/C# support to pulumitest
This commit adds comprehensive support for testing .NET/C# Pulumi applications in the pulumitest library, following existing patterns from Node.js (YarnLink) and Go (GoModReplacement). ## Changes ### Core Functionality - **New `DotNetReference` Option** (`opttest/opttest.go`) - Allows specifying local NuGet packages or projects to reference - Adds `<ProjectReference>` elements to .csproj files on stack creation - Supports both .csproj file paths and directories containing .csproj files - Automatic absolute path resolution - **New `.csproj` Manipulation** (`pulumitest/csproj.go`) - `findCsprojFile()` - Locates .csproj files in a directory - `addProjectReferences()` - Adds ProjectReference elements to .csproj files - Text-based XML manipulation for reliability - **Stack Creation Integration** (`newStack.go`) - Automatic .csproj modification when `DotNetReferences` are specified - Similar pattern to existing `GoModReplacements` and `YarnLinks` ### Test Data - **New Test Programs** - `testdata/csharp_simple/` - Simple C# program using Random provider - `testdata/csharp_aws/` - AWS S3 bucket example - Both use latest package versions: - Pulumi 3.90.0 (latest stable .NET SDK) - Pulumi.Random 4.18.4 - Pulumi.Aws 7.8.0 - Target framework: net8.0 ### Tests - **Unit Tests** (`pulumiTest_test.go`) - `TestDotNetDeploy` - Full deployment workflow - `TestDotNetSkipInstall` - Manual install and stack creation - **Integration Test** (`dotnet_aws_test.go`) - `TestDotNetAwsDeploy` - Real AWS S3 bucket deployment - Verifies automatic cleanup via `t.Cleanup()` ### Documentation - **Updated `pulumitest/CLAUDE.md`** - Added `DotNetReference` to key options - Added .NET/C# SDK configuration section - Added `csproj.go` to file organization - **New `DOTNET-TODO.md`** - Tracks completed items and future enhancements ## Testing All tests pass successfully: - ✅ `TestDotNetDeploy` - Deploys Random provider resources - ✅ `TestDotNetSkipInstall` - Manual installation flow - ✅ `TestDotNetAwsDeploy` - Real AWS S3 bucket deployment and cleanup - ✅ Existing tests remain unaffected ## Example Usage ```go // Basic .NET project test test := NewPulumiTest(t, "path/to/csharp/project") up := test.Up(t) // Test with local SDK reference test := NewPulumiTest(t, "path/to/csharp/project", opttest.DotNetReference("Pulumi.Aws", "../pulumi-aws/sdk/dotnet"), ) ``` ## Notes - Installation via `pulumi install` already supports .NET - The Pulumi .NET SDK uses different versioning than the CLI (3.90.0 vs 3.200+) - Future enhancements tracked in DOTNET-TODO.md
1 parent fe0a2a7 commit 40de799

39 files changed

+2439
-0
lines changed

CLAUDE.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build Commands
6+
- Run all tests: `go test -v -coverprofile="coverage.txt" -coverpkg=./... ./...`
7+
- Run a single test: `go test -v github.com/pulumi/providertest/pulumitest -run TestName`
8+
- Run tests in a specific package: `go test -v github.com/pulumi/providertest/pulumitest`
9+
- Run with race detection: `go test -race ./...`
10+
- Check for lint issues: `golangci-lint run`
11+
- Use Makefile shortcut: `make test` (runs full test suite with coverage)
12+
13+
## Architecture
14+
15+
This library is designed for testing Pulumi providers and programs. It consists of several key modules:
16+
17+
### Core Module: `pulumitest`
18+
The primary testing module that extends Pulumi's Automation API with testing-specific defaults. Key components:
19+
- `PulumiTest`: Main test harness that manages test lifecycle (copying programs, installing dependencies, creating stacks)
20+
- `PT`: Testing interface that wraps Go's `testing.T` with additional test-specific methods
21+
- Functional options pattern via `opttest.Option` for configuration (e.g., `AttachProvider`, `TestInPlace`, `SkipInstall`)
22+
- Operations: `Up()`, `Preview()`, `Refresh()`, `Destroy()`, `Import()` - all accept the test context and options
23+
24+
### Provider Module: `providers`
25+
Utilities for managing providers during tests:
26+
- `ProviderFactory`: Function type that starts providers and returns listening ports
27+
- `ResourceProviderServerFactory`: Creates `pulumirpc.ResourceProviderServer` instances for in-process testing
28+
- Provider attachment modes: attach in-process servers, use local binaries, download specific versions
29+
- `StartProviders()`: Manages multiple provider instances and their lifecycle via context cancellation
30+
31+
### Upgrade Testing
32+
Core functionality in root module for testing provider version upgrades:
33+
- `PreviewProviderUpgrade()`: Records baseline state with old provider version, then previews with new version
34+
- Uses testdata cache directory pattern: `testdata/recorded/TestProviderUpgrade/{programName}/{baselineVersion}`
35+
- Supports replaying invoke calls from recorded gRPC logs to avoid external dependencies during preview
36+
37+
### Additional Modules
38+
- `grpclog`: Reading/writing Pulumi's gRPC log format (grpc.json files) - includes types for parsing and manipulating gRPC logs, with sanitization support for secrets
39+
- `replay`: Exercising provider gRPC methods directly from log files:
40+
- `Replay()`: Executes a single gRPC request against a provider and asserts response matches expected pattern
41+
- `ReplaySequence()`: Replays multiple gRPC events in order from a JSON array
42+
- `ReplayFile()`: Replays all ResourceProvider events from a PULUMI_DEBUG_GRPC log file
43+
- Uses pattern matching (e.g., "*" wildcards) to handle non-deterministic responses
44+
- `optproviderupgrade`: Options for `PreviewProviderUpgrade()` including cache directory templates and baseline options
45+
- `optrun`: Options for the `Run()` method, including caching and option layering
46+
- `optnewstack`: Options for stack creation, including auto-destroy configuration
47+
- Assertion modules (`assertup`, `assertpreview`, `assertrefresh`): Functions for asserting operation results like `HasNoChanges()`, `HasNoDeletes()`
48+
49+
## Testing Patterns
50+
- Tests use temporary directories by default (copied from source with `CopyToTempDir()`)
51+
- Stack state stored locally in temporary directories with fixed passphrase for deterministic encryption
52+
- Use `opttest.TestInPlace()` to run tests without copying (for performance or specific requirements)
53+
- Helper functions call `t.Helper()` to ensure correct test failure line numbers
54+
- Context cancellation via `t.Cleanup()` ensures proper resource cleanup
55+
56+
## Code Style
57+
- Imports: Standard library first, third-party second, grouped by package source with blank line separators
58+
- Functions: CamelCase for exported, camelCase for unexported; descriptive verb-prefixed names
59+
- Variables: camelCase with descriptive names; single letters only for short-lived scopes
60+
- Types: Custom types defined at package level with clear purpose; interfaces with method comments
61+
- Testing: Use t.Parallel() for concurrent tests; use sub-tests with t.Run() for test organization
62+
- Documentation: Add comments for exported functions, types, and variables
63+
64+
## Error Handling
65+
- Return errors as last return value
66+
- Check errors immediately after function calls
67+
- Use fmt.Errorf for error wrapping with context
68+
- Early returns on error conditions
69+
- Helper functions for common error handling patterns
70+
71+
## Pull Requests
72+
- Keep PRs focused on a single concern
73+
- Add tests for new functionality
74+
- Ensure tests pass before submission
75+
- Follow existing code patterns when adding new functionality

DOTNET-TODO.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# .NET Support Implementation TODO
2+
3+
This document tracks the implementation of .NET/C# support for the pulumitest library.
4+
5+
## High Priority (Required for basic support)
6+
7+
### ✅ 1. Installation Support
8+
- Status: Already works via `pulumi install`
9+
- The current implementation delegates to `dotnet restore` automatically
10+
11+
### ✅ 2. Test Data with .NET Examples
12+
- [x] Create `testdata/csharp_simple/` directory
13+
- [x] Add `Pulumi.yaml` with `runtime: dotnet`
14+
- [x] Add `.csproj` file with Pulumi package references
15+
- [x] Add `Program.cs` with simple resource definitions
16+
- [x] Create `testdata/csharp_aws/` directory for AWS provider tests
17+
- [ ] Create `testdata/fsharp_simple/` directory for F# support validation (deferred)
18+
19+
### ✅ 3. .NET Package Reference Option
20+
- [x] Add `DotNetReferences` field to `Options` struct in `opttest/opttest.go`
21+
- [x] Implement `DotNetReference()` option function
22+
- [x] Implement .csproj manipulation logic in `newStack.go`
23+
- [x] Parse existing .csproj XML (text-based manipulation)
24+
- [x] Add `<ProjectReference>` elements
25+
- [x] Handle absolute path resolution
26+
- [x] Write modified .csproj back to disk
27+
- [x] Update `Defaults()` function to initialize .NET fields
28+
- [x] Created `csproj.go` helper file with functions:
29+
- `findCsprojFile()` - finds .csproj in a directory
30+
- `addProjectReferences()` - adds ProjectReference elements to .csproj
31+
32+
### ✅ 4. Basic .NET Integration Tests
33+
- [x] Add `TestDotNetDeploy` - Basic deployment test with preview, up, and second preview
34+
- [x] Add `TestDotNetSkipInstall` - Test with manual install and stack creation
35+
- [x] Tests verified passing with .NET 8.0
36+
- [x] Add `TestDotNetWithLocalReference` - Test local package references
37+
- [x] Add `TestDotNetAwsDeploy` - Real AWS S3 bucket deployment and verification
38+
39+
## Medium Priority (Nice to have)
40+
41+
### ✅ 5. Build Configuration Options
42+
- [x] Add `DotNetBuildConfig` field to Options struct
43+
- [x] Implement `DotNetBuildConfiguration()` option (Debug/Release)
44+
- [x] Pass configuration via `DOTNET_BUILD_CONFIGURATION` environment variable
45+
46+
### ✅ 6. Target Framework Specification
47+
- [x] Add `DotNetTargetFramework` field to Options struct
48+
- [x] Implement `DotNetTargetFramework()` option (net6.0, net7.0, net8.0, etc.)
49+
- [x] Handle framework selection in .csproj manipulation via `setTargetFramework()`
50+
- [x] Added to Options struct and integrated in newStack.go
51+
52+
### 7. NuGet.config Handling
53+
- [ ] Support for custom NuGet feeds
54+
- [ ] Option to specify NuGet.config path
55+
- [ ] Auto-detection of NuGet.config in project directory
56+
57+
## Low Priority (Optional enhancements)
58+
59+
### 8. MSBuild Verbosity Controls
60+
- [ ] Option to control build output verbosity
61+
- [ ] Environment variable configuration
62+
63+
### 9. Custom dotnet CLI Arguments
64+
- [ ] Generic option to pass additional arguments to dotnet commands
65+
- [ ] Support for dotnet build arguments
66+
- [ ] Support for dotnet restore arguments
67+
68+
### 10. Multi-targeting Support
69+
- [ ] Handle projects with multiple target frameworks
70+
- [ ] Option to select specific framework for testing
71+
72+
## Documentation
73+
74+
### ✅ 11. Update Documentation
75+
- [x] Update `pulumitest/CLAUDE.md` with .NET support details
76+
- [x] Added all .NET options to key options list (`DotNetReference`, `DotNetBuildConfiguration`, `DotNetTargetFramework`)
77+
- [x] Added comprehensive .NET/C# SDK configuration section with detailed usage
78+
- [x] Added `csproj.go` to file organization
79+
- [x] Added troubleshooting section for common .NET issues
80+
- [x] Added code examples section with 3 usage patterns
81+
- [x] Checked root README.md (no updates needed - remains language-agnostic)
82+
83+
### ✅ 12. Code Examples
84+
- [x] Added examples in `pulumitest/CLAUDE.md` showing:
85+
- Basic .NET test
86+
- Test with local SDK reference using `DotNetReference`
87+
- Test with specific framework and configuration
88+
- [x] Created comprehensive test data:
89+
- `testdata/csharp_simple/` - Simple Random provider example
90+
- `testdata/csharp_aws/` - AWS S3 bucket example
91+
- `testdata/csharp_with_ref/` - Program using local project reference
92+
- `testdata/mock_sdk/` - Mock SDK for reference testing
93+
94+
## Testing Strategy
95+
96+
### Unit Tests
97+
- [ ] Test .csproj XML parsing and modification
98+
- [ ] Test option parsing and application
99+
- [ ] Test path resolution for .NET references
100+
101+
### Integration Tests
102+
- [ ] Test with .NET 6, 7, and 8
103+
- [ ] Test with C# and F# projects
104+
- [ ] Test with various Pulumi providers (AWS, Azure, GCP)
105+
- [ ] Test local SDK development workflow
106+
107+
## Code Locations
108+
109+
### Files to Modify
110+
1. `/pulumitest/opttest/opttest.go` - Add .NET options (~lines 100-246)
111+
2. `/pulumitest/newStack.go` - Implement .csproj manipulation (after line 172)
112+
3. `/pulumitest/testdata/` - Add .NET test programs
113+
4. `/pulumitest/pulumiTest_test.go` - Add .NET integration tests
114+
5. `/pulumitest/CLAUDE.md` - Document .NET support
115+
6. `/CLAUDE.md` - Update root documentation if needed
116+
117+
### New Files to Create
118+
1. `/pulumitest/testdata/csharp_simple/Pulumi.yaml`
119+
2. `/pulumitest/testdata/csharp_simple/Program.cs`
120+
3. `/pulumitest/testdata/csharp_simple/{ProjectName}.csproj`
121+
4. Additional test data directories as needed
122+
123+
## Summary of Completed Work
124+
125+
### ✅ High Priority - COMPLETE
126+
All basic .NET support features have been implemented and tested:
127+
- Installation works via `pulumi install` (delegates to `dotnet restore`)
128+
- Test data with C# examples (csharp_simple, csharp_aws)
129+
- `DotNetReference()` option for local package/project references
130+
- `.csproj` manipulation helpers: `addProjectReferences()`, `setTargetFramework()`
131+
- Comprehensive integration tests:
132+
- `TestDotNetDeploy` - Full deployment workflow
133+
- `TestDotNetSkipInstall` - Manual install flow
134+
- `TestDotNetWithLocalReference` - Local reference verification
135+
- `TestDotNetAwsDeploy` - Real AWS S3 deployment
136+
137+
### ✅ Medium Priority - COMPLETE
138+
Enhanced .NET support features:
139+
- `DotNetBuildConfiguration()` for Debug/Release builds (via environment variable)
140+
- `DotNetTargetFramework()` for framework selection (.csproj modification)
141+
- Full documentation with examples and troubleshooting
142+
143+
### 🔲 Low Priority (Future Enhancements)
144+
Optional features not yet implemented:
145+
- Item 7: NuGet.config handling (custom feeds, auto-detection)
146+
- Item 8: MSBuild verbosity controls
147+
- Item 9: Custom dotnet CLI arguments
148+
- Item 10: Multi-targeting support
149+
150+
### 🔲 Additional Testing (Future)
151+
- Test with .NET 6 and 7 (currently only testing with 8)
152+
- F# project support validation
153+
- Azure and GCP provider examples
154+
- Multi-project .NET solution testing
155+
156+
## Implementation Summary
157+
158+
**Files Modified:**
159+
- `/pulumitest/opttest/opttest.go` - Added 3 .NET options and 2 fields to Options struct
160+
- `/pulumitest/newStack.go` - Integrated .csproj manipulation during stack creation
161+
- `/pulumitest/pulumiTest_test.go` - Added 3 .NET integration tests
162+
- `/pulumitest/CLAUDE.md` - Comprehensive documentation, examples, and troubleshooting
163+
164+
**Files Created:**
165+
- `/pulumitest/csproj.go` - Helper functions for .csproj manipulation
166+
- `/pulumitest/dotnet_aws_test.go` - Real AWS deployment integration test
167+
- `/pulumitest/testdata/csharp_simple/*` - Simple Random provider test program
168+
- `/pulumitest/testdata/csharp_aws/*` - AWS S3 bucket test program
169+
- `/pulumitest/testdata/csharp_with_ref/*` - Local reference test program
170+
- `/pulumitest/testdata/mock_sdk/*` - Mock SDK for testing references
171+
172+
**Package Versions Used:**
173+
- Pulumi: 3.90.0 (latest stable .NET SDK)
174+
- Pulumi.Random: 4.18.4
175+
- Pulumi.Aws: 7.8.0
176+
- Target Framework: net8.0
177+
178+
**Status:****Production-ready for basic and intermediate .NET testing workflows**
179+
180+
## Original Estimated Effort vs. Actual
181+
182+
- **Original Estimate**: 1-2 weeks for production-ready support
183+
- **High Priority**: Completed
184+
- **Medium Priority**: Completed
185+
- **Low Priority**: Deferred to future enhancements
186+
- **Documentation**: Completed with examples and troubleshooting
187+
188+
## Notes
189+
190+
- The architecture is well-designed and extensible - following existing patterns from `YarnLink` and `GoModReplacement` worked excellently
191+
- Most Automation API functionality already supported .NET - main work was language-specific package management
192+
- The `.csproj` manipulation uses text-based approach for reliability and simplicity
193+
- All tests pass including end-to-end AWS deployment with automatic cleanup

0 commit comments

Comments
 (0)