mirror of
https://github.com/nabbar/golib.git
synced 2025-12-24 11:51:02 +08:00
[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
598 lines
14 KiB
Markdown
598 lines
14 KiB
Markdown
# Testing Guide - Certificates Package
|
|
|
|
[](https://opensource.org/licenses/MIT)
|
|
[](https://golang.org/)
|
|
|
|
Comprehensive testing documentation for the certificates package and subpackages.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [Test Framework](#test-framework)
|
|
- [Running Tests](#running-tests)
|
|
- [Test Coverage](#test-coverage)
|
|
- [Test Organization](#test-organization)
|
|
- [Writing Tests](#writing-tests)
|
|
- [Best Practices](#best-practices)
|
|
- [Troubleshooting](#troubleshooting)
|
|
- [Contributing](#contributing)
|
|
- [Resources](#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
|
|
|
|
1. **Behavior-Driven**: Tests describe behavior in readable, hierarchical structures
|
|
2. **Security-Focused**: Verify secure defaults and TLS configuration correctness
|
|
3. **Format Coverage**: Test multiple encoding formats (JSON, YAML, TOML, CBOR)
|
|
4. **Parser Robustness**: Test parsing with valid and invalid inputs
|
|
5. **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](https://onsi.github.io/ginkgo/) is a BDD-style testing framework providing:
|
|
- Hierarchical test organization (`Describe`, `Context`, `It` blocks)
|
|
- Setup/teardown hooks (`BeforeEach`, `AfterEach`, `DeferCleanup`)
|
|
- Parallel test execution
|
|
- Rich CLI with filtering and reporting
|
|
- Excellent failure diagnostics
|
|
|
|
### Gomega
|
|
|
|
[Gomega](https://onsi.github.io/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**
|
|
```bash
|
|
# 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`)
|
|
```bash
|
|
# 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**
|
|
```bash
|
|
go test -coverprofile=coverage.out ./...
|
|
go tool cover -html=coverage.out -o coverage.html
|
|
```
|
|
|
|
**View Coverage by Function**
|
|
```bash
|
|
go test -coverprofile=coverage.out ./...
|
|
go tool cover -func=coverage.out
|
|
```
|
|
|
|
### Advanced Options
|
|
|
|
**Focus on Specific Tests**
|
|
```bash
|
|
# Run tests matching pattern
|
|
ginkgo --focus="Parse" -r
|
|
|
|
# Skip tests matching pattern
|
|
ginkgo --skip="Encoding" -r
|
|
```
|
|
|
|
**Output Formats**
|
|
```bash
|
|
# JUnit XML report (CI integration)
|
|
ginkgo --junit-report=test-results.xml -r
|
|
|
|
# JSON output
|
|
ginkgo --json-report=test-results.json -r
|
|
```
|
|
|
|
**Specific Packages**
|
|
```bash
|
|
# 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
|
|
|
|
```go
|
|
// 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**
|
|
```go
|
|
// ✅ 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)
|
|
```go
|
|
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**
|
|
```go
|
|
// 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**
|
|
```go
|
|
// 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**
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
```go
|
|
// ✅ 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
|
|
```go
|
|
// ✅ 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
|
|
```go
|
|
// ✅ 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
|
|
```go
|
|
// ✅ 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*:
|
|
```go
|
|
// 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*:
|
|
```bash
|
|
# Verify encoding with actual output
|
|
ginkgo -v --focus="Encoding"
|
|
```
|
|
|
|
**Stale Coverage**
|
|
|
|
*Problem*: Coverage report doesn't reflect recent changes.
|
|
|
|
*Solution*:
|
|
```bash
|
|
go clean -testcache
|
|
go test -coverprofile=coverage.out ./...
|
|
```
|
|
|
|
### Debugging Techniques
|
|
|
|
**Run Specific Tests**
|
|
```bash
|
|
# Focus on specific package
|
|
cd auth
|
|
go test -v
|
|
|
|
# Focus on specific test
|
|
ginkgo --focus="Parse" -v
|
|
```
|
|
|
|
**Verbose Output**
|
|
```bash
|
|
# Ginkgo verbose mode
|
|
ginkgo -v --trace -r
|
|
|
|
# Standard Go verbose
|
|
go test -v ./...
|
|
```
|
|
|
|
**Check Test Data**
|
|
```go
|
|
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**
|
|
1. Choose appropriate test file based on feature
|
|
2. Use descriptive test names
|
|
3. Follow AAA pattern (Arrange, Act, Assert)
|
|
4. Test multiple input formats
|
|
5. Test edge cases and error conditions
|
|
6. 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**
|
|
- [Ginkgo v2 Documentation](https://onsi.github.io/ginkgo/)
|
|
- [Gomega Matcher Reference](https://onsi.github.io/gomega/)
|
|
- [Go Testing Package](https://pkg.go.dev/testing)
|
|
- [Go crypto/tls](https://pkg.go.dev/crypto/tls)
|
|
|
|
**Certificates Package**
|
|
- [Package GoDoc](https://pkg.go.dev/github.com/nabbar/golib/certificates)
|
|
- [README.md](README.md) - Package overview and examples
|
|
- [GitHub Repository](https://github.com/nabbar/golib)
|
|
|
|
**Testing Tools**
|
|
- [Go Test Command](https://pkg.go.dev/cmd/go#hdr-Test_packages)
|
|
- [Coverage Tool](https://go.dev/blog/cover)
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
MIT License - See [LICENSE](../../LICENSE) file for details.
|