Test File Format ​
Complete specification of the .gctf
(gRPC Testify Configuration File) format.
File Structure ​
A .gctf
file consists of sections separated by --- SECTION_NAME ---
markers:
--- ADDRESS ---
localhost:4770
--- ENDPOINT ---
service.Method
--- REQUEST ---
{
"field": "value"
}
--- RESPONSE ---
{
"result": "*"
}
--- ASSERTS ---
.result | length > 0
Core Sections ​
ADDRESS ​
Required: Server address for gRPC connection.
--- ADDRESS ---
localhost:4770
- Format:
host:port
- Examples:
api.example.com:443
,127.0.0.1:9090
- Environment Override:
GRPCTESTIFY_ADDRESS
ENDPOINT ​
Required: gRPC service method to call.
--- ENDPOINT ---
package.ServiceName/MethodName
- Format:
package.Service/Method
- Examples:
user.UserService/CreateUser
,chat.ChatService/SendMessage
REQUEST ​
Required: JSON request payload.
--- REQUEST ---
{
"username": "alice",
"email": "alice@example.com"
}
- Format: Valid JSON object
- Wildcards: Use
"*"
for generated/dynamic values - Comments:
// Comment
(stripped during processing)
RESPONSE ​
Optional: Expected response structure for validation.
--- RESPONSE ---
{
"user": {
"id": "*",
"username": "alice"
},
"success": true
}
- Wildcards:
"*"
matches any value - Partial matching: Only specified fields are validated
- Type validation: JSON types must match
RESPONSE Inline Options ​
You can add inline options to the RESPONSE section for advanced validation:
--- RESPONSE with_asserts ---
{
"user": {
"id": "*",
"username": "alice"
},
"success": true
}
Available inline options:
with_asserts
: Run ASSERTS section on the same response (for unary RPC)type=partial
: Subset comparison (expected is subset of actual)tolerance=0.1
: Numeric tolerance for floating-point comparisonsredact=field1,field2
: Remove sensitive fields before comparisonunordered_arrays=true
: Sort arrays for order-independent comparison
Note: For unary RPC, use either RESPONSE
OR ASSERTS
, not both. Use RESPONSE with_asserts
if you need both.
Advanced Sections ​
ASSERTS ​
Optional: jq-based assertions for response validation.
Note: --- ASSERT ---
(singular) has been removed. Use --- ASSERTS ---
(plural) instead.
Multiple Response Assertions (Server Streaming) ​
--- ASSERTS ---
.status == "VALIDATION"
.message | contains("Validating")
.progress >= 0
--- ASSERTS ---
.status == "PROCESSING"
.message | contains("Processing")
.progress >= 50
--- ASSERTS ---
.status == "COMPLETED"
.message | contains("Completed")
.progress == 100
Use Cases:
- Server streaming with multiple status updates
- Payment processing stages
- File upload progress
- Alert escalation workflows
- Real-time monitoring updates
Assertion Operators ​
- Equality:
== "value"
,!= "value"
- Comparison:
> 10
,>= 5
,< 100
,<= 50
- String operations:
contains("text")
,startswith("prefix")
,endswith("suffix")
- Pattern matching:
test("regex_pattern")
- Array operations:
length
,empty
,.[0]
- Type checking:
type == "string"
TLS ​
Optional: TLS/mTLS configuration for secure connections.
Basic TLS (Server Authentication Only) ​
--- TLS ---
ca_cert: ./path/to/ca-cert.pem
server_name: api.example.com
insecure_skip_verify: false
Mutual TLS (mTLS with Client Authentication) ​
--- TLS ---
ca_cert: ./../server/tls/ca-cert.pem
cert: ./../server/tls/client-cert.pem
key: ./../server/tls/client-key.pem
server_name: localhost
insecure_skip_verify: false
Parameters:
- ca_cert: Path to CA certificate file (relative to .gctf file)
- cert: Path to client certificate file
- key: Path to client private key file
- server_name: Expected server name in certificate
- insecure_skip_verify: Skip certificate verification (testing only)
Relative Paths: All paths are relative to the .gctf
file location:
./certs/ca.pem
- Same directory./../server/tls/ca.pem
- Parent directory navigation./../../shared/certs/ca.pem
- Multiple level navigation
ERROR ​
Optional: Expected error response validation.
--- ERROR ---
{
"code": 5,
"message": "User not found",
"details": []
}
- code: gRPC status code (0-16)
- message: Error message pattern
- details: Additional error details
REQUEST_HEADERS ​
Optional: Custom request headers for gRPC calls.
--- REQUEST_HEADERS ---
authorization: Bearer token123
x-api-key: secret
x-request-id: req_001
x-client-version: 1.0.0
Format: One header per line in name: value
format Examples:
authorization: Bearer token123
x-api-key: secret
content-type: application/json
Note: The HEADERS
section is deprecated. Use REQUEST_HEADERS
instead.
Headers/Trailers Plugin System ​
Modern approach: Use plugin syntax for response header and trailer validation.
Header Validation ​
--- ASSERTS ---
.success == true
@header("x-response-time") == "150ms"
@header("x-server-version") == "1.0.0"
@header("x-request-id") | test("req-.*")
Trailer Validation ​
--- ASSERTS ---
.success == true
@trailer("x-processing-time") == "45ms"
@trailer("x-cache-hit") == "false"
@trailer("x-rate-limit-remaining") | test("[0-9]+")
Plugin Syntax:
@header("name") == "value"
- Exact header value match@header("name") | test("pattern")
- Header value pattern matching@trailer("name") == "value"
- Exact trailer value match@trailer("name") | test("pattern")
- Trailer value pattern matching
Benefits:
- More flexible than separate RESPONSE_HEADERS/RESPONSE_TRAILERS sections
- Integrated with plugin system for consistency
- Supports both exact matching and regex patterns
- Can be combined with other assertions in ASSERTS section
Legacy Headers/Trailers (REMOVED) ​
Note: The following sections have been removed. Use @header()
and @trailer()
assertions instead.
# ❌ REMOVED - Use @header()/@trailer() instead
--- RESPONSE_HEADERS ---
--- RESPONSE_TRAILERS ---
# âś… Use this instead:
--- ASSERTS ---
@header("x-response-time") | test("\\d+ms")
@trailer("x-execution-time") | test("\\d+ms")
PROTO ​
Optional: Protocol buffer configuration for gRPC reflection or descriptor files.
--- PROTO ---
mode: reflection
files: []
import_paths: []
descriptor: ""
Parameters:
- mode:
reflection
(default) ordescriptor
- files: Array of .proto file paths
- import_paths: Array of import directories
- descriptor: Path to compiled descriptor file
OPTIONS ​
Optional: Test execution options.
--- OPTIONS ---
timeout: 30
tolerance: 0.1
partial: true
redact: ["password", "token"]
Advanced Examples ​
Payment Processing with Multiple Status Updates ​
--- ENDPOINT ---
payment.PaymentService/ProcessPayment
--- REQUEST ---
{
"payment_id": "pay_12345"
}
--- ASSERTS ---
.status == "VALIDATION"
.progress_percentage <= 20
--- ASSERTS ---
.status == "PROCESSING"
.progress_percentage >= 20
.progress_percentage <= 80
--- ASSERTS ---
.status == "COMPLETED"
.progress_percentage == 100
Secure File Upload with TLS ​
--- TLS ---
ca_cert: ./../server/tls/ca-cert.pem
cert: ./../server/tls/client-cert.pem
key: ./../server/tls/client-key.pem
server_name: localhost
--- ENDPOINT ---
files.FileService/SecureUpload
--- REQUEST ---
{
"filename": "document.pdf",
"encryption": "AES256"
}
--- ASSERTS ---
.status == "ENCRYPTED"
.file_id | test("secure_.*")
Alert Escalation Workflow ​
--- ENDPOINT ---
monitoring.AlertService/ProcessAlert
--- ASSERTS ---
.stage == "RECEIVED"
.processing_time < 1000
--- ASSERTS ---
.stage == "CORRELATION"
.related_alerts | length >= 0
--- ASSERTS ---
.stage == "ESCALATION"
.escalation_level == 2
Headers/Trailers Validation with Plugin System ​
--- ENDPOINT ---
shopflow.ShopFlowService/CreateProduct
--- REQUEST ---
{
"name": "Test Product with Headers",
"description": "Product to test response headers and trailers",
"price": 99.99,
"currency": "USD",
"stock_quantity": 10,
"categories": ["Test"],
"sku": "TEST-001"
}
--- ASSERTS ---
.success == true
.product.id | type == "string"
.product.name == "Test Product with Headers"
.product.price == 99.99
@header("x-response-time") == "150ms"
@header("x-server-version") == "1.0.0"
@header("x-request-id") == "req-12345"
@trailer("x-processing-time") == "45ms"
@trailer("x-cache-hit") == "false"
@trailer("x-rate-limit-remaining") == "999"
Validation Rules ​
JSON Validation ​
- All JSON must be valid and parseable
- Comments are stripped before parsing
- Trailing commas are not allowed
Path Resolution ​
- Relative paths start from
.gctf
file location - Use forward slashes
/
for cross-platform compatibility - Tilde
~
expansion not supported in relative paths
Variable Substitution ​
- Environment variables:
${ENV_VAR}
or$ENV_VAR
- Built-in variables:
${TIMESTAMP}
,${UUID}
,${RANDOM}
Best Practices ​
File Organization ​
tests/
├── auth/
│ ├── login.gctf
│ ├── logout.gctf
│ └── refresh_token.gctf
├── users/
│ ├── create_user.gctf
│ ├── get_user.gctf
│ └── update_user.gctf
└── shared/
└── tls/
├── ca-cert.pem
├── client-cert.pem
└── client-key.pem
Naming Conventions ​
- Use descriptive filenames:
user_creation_success.gctf
- Group related tests in directories
- Use consistent prefixes:
error_
,success_
,tls_
Security ​
- Never commit private keys to version control
- Use environment variables for sensitive data
- Rotate test certificates regularly
- Use
insecure_skip_verify: true
only for testing
Common Patterns ​
Error Testing ​
--- REQUEST ---
{
"invalid_field": "value"
}
--- ERROR ---
{
"code": 3,
"message": "invalid argument"
}
Performance Testing ​
--- OPTIONS ---
timeout: 5
--- ASSERTS ---
.processing_time_ms < 1000
Authentication Testing ​
--- REQUEST_HEADERS ---
authorization: Bearer ${API_TOKEN}
--- ASSERTS ---
.authenticated == true