[root] - UPDATE documentation: enhanced README and TESTING guidelines - UPDATE security md file: fix minimal go version needed - ADD script: add coverage_report.sh script (see TESTING for info) [ioutils/aggregator] - ADD package: add new package to simplify aggregation of multiple write to a unique writer function - ADD documentation: add enhanced README and TESTING guidelines - ADD tests: complete test suites with benchmarks, concurrency, and edge cases [router] - UPDATE documentation [semaphore] - FIX bug if given context is nil or have error trigger [shell] - UPDATE package & sub-package: fix bugs and optimize code - ADD sub-package tty: allow to backup and restore tty setting - ADD documentation: add enhanced README and TESTING guidelines - ADD tests: complete test suites with benchmarks, concurrency, and edge cases [socket] - UPDATE package & sub-package: rename function Handler to HandlerFunc - UPDATE package & sub-package: add new interface Handler to expose a socket compatible handler function [Other] - UPDATE go.mod: bump dependencies
14 KiB
Testing Guide - Certificates Package
Comprehensive testing documentation for the certificates package and subpackages.
Table of Contents
- Overview
- Test Framework
- Running Tests
- Test Coverage
- Test Organization
- Writing Tests
- Best Practices
- Troubleshooting
- Contributing
- Resources
Overview
The certificates package uses Ginkgo v2 (BDD testing framework) and Gomega (matcher library) to achieve comprehensive test coverage across all subpackages.
Test Philosophy
- Behavior-Driven: Tests describe behavior in readable, hierarchical structures
- Security-Focused: Verify secure defaults and TLS configuration correctness
- Format Coverage: Test multiple encoding formats (JSON, YAML, TOML, CBOR)
- Parser Robustness: Test parsing with valid and invalid inputs
- Maintainable: Clear test structure with reusable patterns
Coverage Scope
- ✅ TLS configuration management and generation
- ✅ Certificate parsing and validation
- ✅ CA certificate management (root and client)
- ✅ TLS version, cipher suite, and curve configuration
- ✅ Client authentication modes
- ✅ Multiple encoding formats (JSON, YAML, TOML, CBOR)
- ✅ Parser edge cases and error handling
Test Framework
Ginkgo v2
Ginkgo is a BDD-style testing framework providing:
- Hierarchical test organization (
Describe,Context,Itblocks) - Setup/teardown hooks (
BeforeEach,AfterEach,DeferCleanup) - Parallel test execution
- Rich CLI with filtering and reporting
- Excellent failure diagnostics
Gomega
Gomega is the matcher library offering:
- Readable assertion syntax:
Expect(value).To(Equal(expected)) - Extensive built-in matchers
- Detailed failure messages
- Custom matcher support
Running Tests
Quick Start
Standard Go Testing
# Run all tests
go test ./...
# With verbose output
go test -v ./...
# With coverage
go test -cover ./...
# With race detection (recommended)
CGO_ENABLED=1 go test -race ./...
Ginkgo CLI (install: go install github.com/onsi/ginkgo/v2/ginkgo@latest)
# Run all tests recursively
ginkgo -r
# Verbose output
ginkgo -v -r
# With coverage
ginkgo -cover -r
# Parallel execution
ginkgo -p -r
# Watch mode (re-run on file changes)
ginkgo watch -r
Coverage Reports
Generate HTML Coverage Report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
View Coverage by Function
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
Advanced Options
Focus on Specific Tests
# Run tests matching pattern
ginkgo --focus="Parse" -r
# Skip tests matching pattern
ginkgo --skip="Encoding" -r
Output Formats
# JUnit XML report (CI integration)
ginkgo --junit-report=test-results.xml -r
# JSON output
ginkgo --json-report=test-results.json -r
Specific Packages
# Test only main package
cd /path/to/golib/certificates
go test .
# Test specific subpackage
cd auth
go test .
Test Coverage
Coverage Metrics
| Package | Coverage | Specs | Description |
|---|---|---|---|
certificates |
~70% | 15 | Main TLS configuration |
auth |
73.0% | 12 | Client authentication modes |
ca |
68.5% | 18 | CA certificate management |
certs |
47.8% | 9 | Certificate pair management |
cipher |
50.6% | 12 | Cipher suite configuration |
curves |
50.5% | 9 | Elliptic curve configuration |
tlsversion |
54.5% | 9 | TLS version management |
| Total | ~60% | 84 | All packages |
Coverage by Component
Main Package (certificates_config_test.go - 15 specs)
- TLS configuration creation and validation
- Certificate pair management
- Root CA and Client CA operations
- Version, cipher, and curve configuration
- TLS config generation
auth Package (auth_test.go - 12 specs)
- Parse client authentication modes from strings
- Parse from integer values
- Encoding/decoding (JSON, YAML, TOML, CBOR)
- String representation and validation
- TLS type conversion
ca Package (ca_test.go - 18 specs)
- Parse CA certificates from PEM strings
- Parse certificate chains
- File path handling
- Certificate pool operations
- Encoding/decoding in multiple formats
- Error handling for invalid certificates
certs Package (certs_test.go - 9 specs)
- Parse certificate pairs from PEM
- Parse from ConfigPair and ConfigChain
- Certificate validation
- TLS certificate generation
- Encoding/decoding
cipher Package (cipher_test.go - 12 specs)
- Parse cipher suites from strings
- List available cipher suites
- Validate cipher suite IDs
- String representation
- Encoding/decoding
curves Package (curves_test.go - 9 specs)
- Parse elliptic curves from strings
- List available curves
- Validate curve IDs
- String representation
- Encoding/decoding
tlsversion Package (tlsversion_test.go - 9 specs)
- Parse TLS versions from strings
- Parse from integer values
- List available versions
- String representation
- Encoding/decoding
Test Organization
File Structure
certificates/
├── certificates_suite_test.go # Main test suite setup
├── certificates_config_test.go # TLS configuration tests (15 specs)
└── Subpackages/
├── auth/
│ ├── auth_suite_test.go # Auth test suite setup
│ └── auth_test.go # Auth mode tests (12 specs)
├── ca/
│ ├── ca_suite_test.go # CA test suite setup
│ └── ca_test.go # CA certificate tests (18 specs)
├── certs/
│ ├── certs_suite_test.go # Certs test suite setup
│ └── certs_test.go # Certificate pair tests (9 specs)
├── cipher/
│ ├── cipher_suite_test.go # Cipher test suite setup
│ └── cipher_test.go # Cipher suite tests (12 specs)
├── curves/
│ ├── curves_suite_test.go # Curves test suite setup
│ └── curves_test.go # Elliptic curve tests (9 specs)
└── tlsversion/
├── tlsversion_suite_test.go # Version test suite setup
└── tlsversion_test.go # TLS version tests (9 specs)
Test Structure Pattern
// Hierarchical BDD structure
Describe("certificates/Feature", func() {
Context("When parsing input", func() {
It("should parse valid PEM string", func() {
// Arrange
pemData := `-----BEGIN CERTIFICATE-----...`
// Act
cert, err := ca.Parse(pemData)
// Assert
Expect(err).ToNot(HaveOccurred())
Expect(cert).ToNot(BeNil())
Expect(cert.Len()).To(Equal(1))
})
It("should return error for invalid input", func() {
// Arrange
invalid := "not a certificate"
// Act
_, err := ca.Parse(invalid)
// Assert
Expect(err).To(HaveOccurred())
})
})
})
Writing Tests
Test Guidelines
1. Descriptive Test Names
// ✅ Good: Clear, specific description
It("should parse ECDHE-RSA-AES128-GCM-SHA256 cipher suite", func() {
// Test implementation
})
// ❌ Bad: Vague description
It("should work", func() {
// Test implementation
})
2. Follow AAA Pattern (Arrange, Act, Assert)
It("should parse TLS version from string", func() {
// Arrange
input := "1.2"
// Act
version := tlsversion.Parse(input)
// Assert
Expect(version).To(Equal(tlsversion.VersionTLS12))
})
3. Test Multiple Formats
// Test encoding/decoding for all supported formats
It("should marshal to JSON", func() {
auth := auth.RequireAndVerifyClientCert
data, err := json.Marshal(auth)
Expect(err).ToNot(HaveOccurred())
Expect(string(data)).To(ContainSubstring("require"))
})
It("should unmarshal from JSON", func() {
var auth auth.ClientAuth
err := json.Unmarshal([]byte(`"verify"`), &auth)
Expect(err).ToNot(HaveOccurred())
Expect(auth).To(Equal(auth.VerifyClientCertIfGiven))
})
4. Test Edge Cases
// Test with empty, nil, invalid, and boundary inputs
It("should handle empty string", func() {
version := tlsversion.Parse("")
Expect(version).To(Equal(tlsversion.VersionUnknown))
})
It("should handle invalid cipher suite ID", func() {
valid := cipher.Check(0xFFFF)
Expect(valid).To(BeFalse())
})
5. Test Security Properties
It("should default to secure TLS version", func() {
cfg := certificates.New()
min := cfg.GetVersionMin()
Expect(min).To(Or(
Equal(tlsversion.VersionTLS12),
Equal(tlsversion.VersionTLS13),
))
})
Test Template
var _ = Describe("certificates/NewFeature", func() {
Context("When feature is used", func() {
It("should perform expected behavior", func() {
// Arrange
cfg := certificates.New()
// Act
cfg.SetVersionMin(tlsversion.VersionTLS12)
version := cfg.GetVersionMin()
// Assert
Expect(version).To(Equal(tlsversion.VersionTLS12))
})
It("should handle edge case", func() {
// Test edge case
cfg := certificates.New()
certs := cfg.GetCertificatePair()
Expect(certs).To(BeEmpty())
})
})
})
Best Practices
Test Independence
// ✅ Good: Each test creates its own config
It("should add certificate", func() {
cfg := certificates.New()
err := cfg.AddCertificatePairFile("key.pem", "cert.pem")
Expect(err).ToNot(HaveOccurred())
})
// ❌ Bad: Tests share state
var sharedCfg certificates.TLSConfig
It("test1", func() {
sharedCfg.SetVersionMin(tlsversion.VersionTLS12)
})
It("test2", func() {
// Depends on test1!
version := sharedCfg.GetVersionMin()
})
Parser Testing
// ✅ Good: Test various input formats
It("should parse flexible string formats", func() {
inputs := []string{"1.2", "TLS 1.2", "tls_1_2", "tls12"}
for _, input := range inputs {
version := tlsversion.Parse(input)
Expect(version).To(Equal(tlsversion.VersionTLS12))
}
})
Encoding Testing
// ✅ Good: Test round-trip encoding
It("should round-trip through JSON", func() {
original := cipher.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
// Marshal
data, err := json.Marshal(original)
Expect(err).ToNot(HaveOccurred())
// Unmarshal
var decoded cipher.Cipher
err = json.Unmarshal(data, &decoded)
Expect(err).ToNot(HaveOccurred())
// Verify
Expect(decoded).To(Equal(original))
})
Security Testing
// ✅ Good: Verify secure defaults
It("should use secure cipher suites by default", func() {
cfg := certificates.New()
ciphers := cfg.GetCiphers()
for _, c := range ciphers {
// No weak ciphers
Expect(c).ToNot(Equal(cipher.Unknown))
}
})
Troubleshooting
Common Issues
File Not Found Errors
Problem: Tests fail when loading certificate files.
Solution:
// Use test fixtures or embedded test data
const testCertPEM = `-----BEGIN CERTIFICATE-----
MIIBkTCB+wIJAKHHCgVZU...
-----END CERTIFICATE-----`
It("should parse certificate", func() {
cert, err := ca.Parse(testCertPEM)
Expect(err).ToNot(HaveOccurred())
})
Encoding Mismatches
Problem: Encoding tests fail due to format differences.
Solution:
# Verify encoding with actual output
ginkgo -v --focus="Encoding"
Stale Coverage
Problem: Coverage report doesn't reflect recent changes.
Solution:
go clean -testcache
go test -coverprofile=coverage.out ./...
Debugging Techniques
Run Specific Tests
# Focus on specific package
cd auth
go test -v
# Focus on specific test
ginkgo --focus="Parse" -v
Verbose Output
# Ginkgo verbose mode
ginkgo -v --trace -r
# Standard Go verbose
go test -v ./...
Check Test Data
It("should parse certificate", func() {
cert, err := ca.Parse(pemData)
// Debug output
fmt.Fprintf(GinkgoWriter, "Cert: %+v\n", cert)
fmt.Fprintf(GinkgoWriter, "Error: %v\n", err)
Expect(err).ToNot(HaveOccurred())
})
Contributing
Test Contributions
Guidelines
- Do not use AI to generate test implementation code
- AI may assist with test documentation and bug fixing
- Follow existing test patterns and structure
- Add tests for new features
- Test edge cases and error conditions
Adding New Tests
- Choose appropriate test file based on feature
- Use descriptive test names
- Follow AAA pattern (Arrange, Act, Assert)
- Test multiple input formats
- Test edge cases and error conditions
- Verify security properties
Test Review Checklist
- Tests are independent
- Resources are properly managed
- Edge cases are covered
- Multiple formats tested (JSON, YAML, TOML, CBOR)
- Descriptions are clear
- Security properties verified
- Coverage maintained or improved
AI Transparency Notice
In accordance with Article 50.4 of the EU AI Act, AI assistance has been used for testing, documentation, and bug fixing under human supervision.
Resources
Documentation
Certificates Package
- Package GoDoc
- README.md - Package overview and examples
- GitHub Repository
Testing Tools
License
MIT License - See LICENSE file for details.