Skip to content

Mocker

The simplest way to use the Mocker plugin is with no configuration - it will create a default catch-all rule:

package main
import (
"context"
deepintshield "github.com/maximhq/deepintshield/core"
"github.com/maximhq/deepintshield/core/schemas"
mocker "github.com/maximhq/deepintshield/plugins/mocker"
)
func main() {
// Create plugin with minimal config
plugin, err := mocker.NewMockerPlugin(mocker.MockerConfig{
Enabled: true, // Default rule will be created automatically
})
if err != nil {
panic(err)
}
// Initialize DeepIntShield with the plugin
client, initErr := deepintshield.Init(context.Background(), schemas.DeepIntShieldConfig{
Account: &yourAccount,
LLMPlugins: []schemas.LLMPlugin{plugin},
})
if err != nil {
panic(err)
}
defer client.Shutdown()
// All chat and responses requests will now return: "This is a mock response from the Mocker plugin"
// Chat completion request
chatResponse, _ := client.ChatCompletionRequest(schemas.NewDeepIntShieldContext(context.Background(), schemas.NoDeadline), &schemas.DeepIntShieldChatRequest{
Provider: schemas.OpenAI,
Model: "gpt-4",
Input: []schemas.ChatMessage{
{
Role: schemas.ChatMessageRoleUser,
Content: schemas.ChatMessageContent{
ContentStr: deepintshield.Ptr("Hello!"),
},
},
},
})
// Responses request
responsesResponse, _ := client.ResponsesRequest(schemas.NewDeepIntShieldContext(context.Background(), schemas.NoDeadline), &schemas.DeepIntShieldResponsesRequest{
Provider: schemas.OpenAI,
Model: "gpt-4o",
Input: []schemas.ResponsesMessage{
{
Role: deepintshield.Ptr(schemas.ResponsesInputMessageRoleUser),
Content: &schemas.ResponsesMessageContent{
ContentStr: deepintshield.Ptr("Hello!"),
},
},
},
})
}
plugin, err := mocker.NewMockerPlugin(mocker.MockerConfig{
Enabled: true,
Rules: []mocker.MockRule{
{
Name: "openai-mock",
Enabled: true,
Probability: 1.0, // Always trigger
Conditions: mocker.Conditions{
Providers: []string{"openai"},
},
Responses: []mocker.Response{
{
Type: mocker.ResponseTypeSuccess,
Content: &mocker.SuccessResponse{
Message: "Hello! This is a custom mock response for OpenAI.",
Usage: &mocker.Usage{
PromptTokens: 15,
CompletionTokens: 25,
TotalTokens: 40,
},
},
},
},
},
},
})

The mocker plugin automatically handles both chat completion and responses requests with the same configuration:

// This rule will work for both ChatCompletionRequest and ResponsesRequest
{
Name: "universal-mock",
Enabled: true,
Probability: 1.0,
Conditions: mocker.Conditions{
MessageRegex: stringPtr("(?i).*hello.*"),
},
Responses: []mocker.Response{
{
Type: mocker.ResponseTypeSuccess,
Content: &mocker.SuccessResponse{
Message: "Hello! I'm a mock response that works for both request types.",
},
},
},
}

Add the plugin to your project:

Terminal window
go get github.com/maximhq/deepintshield/plugins/mocker

Import in your code:

import mocker "github.com/maximhq/deepintshield/plugins/mocker"
config := mocker.MockerConfig{
Enabled: true,
DefaultBehavior: mocker.DefaultBehaviorPassthrough, // "passthrough", "success", "error"
Rules: []mocker.MockRule{
// Your rules here
},
}
plugin, err := mocker.NewMockerPlugin(config)
if err != nil {
log.Fatal(err)
}
client, initErr := deepintshield.Init(context.Background(), schemas.DeepIntShieldConfig{
Account: &yourAccount,
LLMPlugins: []schemas.LLMPlugin{plugin},
Logger: deepintshield.NewDefaultLogger(schemas.LogLevelInfo),
})
config := mocker.MockerConfig{
Enabled: false, // All requests pass through to real providers
}

The Mocker plugin supports the following DeepIntShield request types:

  • Chat Completion Requests (ChatCompletionRequest) - Standard chat-based interactions
  • Responses Requests (ResponsesRequest) - OpenAI-compatible responses API format
  • Skip Context Key - Use "skip-mocker" context key to bypass mocking per request

You can skip the mocker plugin for specific requests by adding a context key:

import "github.com/maximhq/deepintshield/core/schemas"
// Create context that skips mocker
ctx := context.WithValue(context.Background(),
schemas.DeepIntShieldContextKey("skip-mocker"), true)
// This request will bypass the mocker and go to the real provider
response, err := client.ChatCompletionRequest(schemas.NewDeepIntShieldContext(ctx, schemas.NoDeadline), request)

Create dynamic responses using templates:

Response{
Type: mocker.ResponseTypeSuccess,
Content: &mocker.SuccessResponse{
MessageTemplate: stringPtr("Hello from {{provider}} using model {{model}}!"),
},
}

Available Variables:

  • {{provider}} - Provider name (e.g., “openai”, “anthropic”)
  • {{model}} - Model name (e.g., “gpt-4”, “claude-3”)
  • {{faker.*}} - Fake data generation (see Configuration Reference)

Configure multiple responses with different probabilities:

Responses: []mocker.Response{
{
Type: mocker.ResponseTypeSuccess,
Weight: 0.8, // 80% chance
Content: &mocker.SuccessResponse{
Message: "Success response",
},
},
{
Type: mocker.ResponseTypeError,
Weight: 0.2, // 20% chance
Error: &mocker.ErrorResponse{
Message: "Rate limit exceeded",
Type: stringPtr("rate_limit"),
Code: stringPtr("429"),
},
},
}

Add realistic delays to responses:

// Fixed latency
Latency: &mocker.Latency{
Type: mocker.LatencyTypeFixed,
Min: 250 * time.Millisecond,
}
// Variable latency
Latency: &mocker.Latency{
Type: mocker.LatencyTypeUniform,
Min: 100 * time.Millisecond,
Max: 500 * time.Millisecond,
}
Conditions: mocker.Conditions{
MessageRegex: stringPtr(`(?i).*support.*|.*help.*`),
}
Conditions: mocker.Conditions{
RequestSize: &mocker.SizeRange{
Min: 100, // bytes
Max: 1000, // bytes
},
}

Create realistic test data using faker variables:

{
Name: "user-profile-example",
Responses: []mocker.Response{
{
Type: mocker.ResponseTypeSuccess,
Content: &mocker.SuccessResponse{
MessageTemplate: stringPtr(`User Profile:
- Name: {{faker.name}}
- Email: {{faker.email}}
- Company: {{faker.company}}
- Address: {{faker.address}}, {{faker.city}}
- Phone: {{faker.phone}}
- User ID: {{faker.uuid}}
- Join Date: {{faker.date}}
- Premium Account: {{faker.boolean}}`),
},
},
},
}

Get runtime statistics for monitoring:

stats := plugin.GetStatistics()
fmt.Printf("Plugin enabled: %v\n", stats.Enabled)
fmt.Printf("Total requests: %d\n", stats.TotalRequests)
fmt.Printf("Mocked requests: %d\n", stats.MockedRequests)
// Rule-specific stats
for ruleName, ruleStats := range stats.Rules {
fmt.Printf("Rule %s: %d triggers\n", ruleName, ruleStats.Triggers)
}
FieldTypeDefaultDescription
EnabledboolfalseEnable/disable the entire plugin
DefaultBehaviorstring"passthrough"Action when no rules match: "passthrough", "success", "error"
GlobalLatency*LatencynilGlobal latency applied to all rules
Rules[]MockRule[]List of mock rules evaluated in priority order
FieldTypeDefaultDescription
Namestring-Unique rule name for identification
EnabledbooltrueEnable/disable this specific rule
Priorityint0Higher numbers = higher priority
Probabilityfloat641.0Activation probability (0.0=never, 1.0=always)
ConditionsConditions{}Matching conditions (empty = match all)
Responses[]Response-Possible responses (weighted random selection)
Latency*LatencynilRule-specific latency override
FieldTypeDescription
Providers[]stringMatch specific providers: ["openai", "anthropic"]
Models[]stringMatch specific models: ["gpt-4", "claude-3"]
MessageRegex*stringRegex pattern to match message content
RequestSize*SizeRangeRequest size constraints in bytes
FieldTypeDescription
TypestringResponse type: "success" or "error"
Weightfloat64Weight for random selection (default: 1.0)
Content*SuccessResponseRequired if Type="success"
Error*ErrorResponseRequired if Type="error"
AllowFallbacks*boolControl fallback behavior (nil=allow, false=block)
FieldTypeDescription
MessagestringStatic response message
MessageTemplate*stringTemplate with variables: {{provider}}, {{model}}, {{faker.*}}
Model*stringOverride model name in response
Usage*UsageToken usage information
FinishReason*stringCompletion reason (default: "stop")
CustomFieldsmap[string]interface{}Additional metadata fields
FieldTypeDescription
MessagestringError message to return
Type*stringError type (e.g., "rate_limit", "auth_error")
Code*stringError code (e.g., "429", "401")
StatusCode*intHTTP status code
FieldTypeDescription
TypestringLatency type: "fixed" or "uniform"
Mintime.DurationMinimum/exact latency (use time.Millisecond)
Maxtime.DurationMaximum latency (required for "uniform")

Important: Use Go’s time.Duration constants:

  • ✅ Correct: 100 * time.Millisecond
  • ❌ Wrong: 100 (nanoseconds, barely noticeable)
  • {{faker.name}} - Full name
  • {{faker.first_name}} - First name only
  • {{faker.last_name}} - Last name only
  • {{faker.email}} - Email address
  • {{faker.phone}} - Phone number
  • {{faker.address}} - Street address
  • {{faker.city}} - City name
  • {{faker.state}} - State/province
  • {{faker.zip_code}} - Postal code
  • {{faker.company}} - Company name
  • {{faker.job_title}} - Job title
  • {{faker.lorem_ipsum}} - Lorem ipsum text
  • {{faker.lorem_ipsum:10}} - Lorem ipsum with 10 words
  • {{faker.uuid}} - UUID v4
  • {{faker.hex_color}} - Hex color code
  • {{faker.integer}} - Random integer (1-100)
  • {{faker.integer:10,50}} - Random integer between 10-50
  • {{faker.float}} - Random float (0-100, 2 decimals)
  • {{faker.float:1,10}} - Random float between 1-10
  • {{faker.boolean}} - Random boolean
  • {{faker.date}} - Date (YYYY-MM-DD format)
  • {{faker.datetime}} - Datetime (YYYY-MM-DD HH:MM:SS format)
// Use priority to control rule evaluation order
rules := []mocker.MockRule{
{Name: "specific-error", Priority: 100, Conditions: /* specific */},
{Name: "general-success", Priority: 50, Conditions: /* general */},
{Name: "catch-all", Priority: 0, Conditions: /* empty */},
}
// Development: High mock rate
config := mocker.MockerConfig{
Enabled: true,
Rules: []mocker.MockRule{
{Probability: 1.0}, // Always mock
},
}
// Production: Occasional testing
config := mocker.MockerConfig{
Enabled: true,
Rules: []mocker.MockRule{
{Probability: 0.1}, // 10% mock rate
},
}
  • Place specific conditions before general ones (higher priority)
  • Use simple string matching over complex regex when possible
  • Keep response templates reasonably sized
  • Consider disabling debug logging in production
func validateMockerConfig(config mocker.MockerConfig) error {
_, err := mocker.NewMockerPlugin(config)
return err
}
// Test before deployment
if err := validateMockerConfig(yourConfig); err != nil {
log.Fatalf("Invalid mocker configuration: %v", err)
}
  1. Check if plugin is enabled: Enabled: true
  2. Verify rule is enabled: rule.Enabled: true
  3. Check probability: Probability: 1.0 for testing
  4. Verify conditions match your request

Use time.Duration constants, not raw integers:

// ❌ Wrong: 100 nanoseconds (barely noticeable)
Min: 100
// ✅ Correct: 100 milliseconds
Min: 100 * time.Millisecond

Test your regex pattern and ensure proper escaping:

// Case-insensitive matching
MessageRegex: stringPtr(`(?i).*help.*`)
// Escape special characters
MessageRegex: stringPtr(`\$\d+\.\d+`) // Match $12.34
Response{
Type: mocker.ResponseTypeError,
AllowFallbacks: boolPtr(false), // Block fallbacks
Error: &mocker.ErrorResponse{
Message: "Authentication failed",
},
}

Ensure you’re using the correct context key format:

// ✅ Correct
ctx := context.WithValue(context.Background(),
schemas.DeepIntShieldContextKey("skip-mocker"), true)
// ❌ Wrong
ctx := context.WithValue(context.Background(), "skip-mocker", true)

If responses requests aren’t being mocked:

  1. Verify the plugin supports ResponsesRequest (version 1.2.13+)
  2. Check that your regex patterns match the message content
  3. Ensure the request type is schemas.ResponsesRequest

Enable debug logging to troubleshoot:

client, initErr := deepintshield.Init(context.Background(), schemas.DeepIntShieldConfig{
Account: &account,
LLMPlugins: []schemas.LLMPlugin{plugin},
Logger: deepintshield.NewDefaultLogger(schemas.LogLevelDebug),
})