golang自动化测试网络环境模拟代理插件toxiproxy的使用

Golang自动化测试网络环境模拟代理插件Toxiproxy的使用

Toxiproxy是一个用于模拟网络条件的框架,专门用于测试、CI和开发环境,支持对连接进行可预测的干扰,同时支持随机化的混乱和自定义配置。

安装Toxiproxy

Linux

可以从Toxiproxy的GitHub Releases页面下载最新二进制文件或系统包。

Ubuntu

wget -O toxiproxy-2.1.4.deb https://github.com/Shopify/toxiproxy/releases/download/v2.1.4/toxiproxy_2.1.4_amd64.deb
sudo dpkg -i toxiproxy-2.1.4.deb
sudo service toxiproxy start

OS X (使用Homebrew)

brew tap shopify/shopify
brew install toxiproxy

Docker

docker pull ghcr.io/shopify/toxiproxy
docker run --rm -it ghcr.io/shopify/toxiproxy

从源码构建

make build
./toxiproxy-server

Golang客户端示例

下面是一个完整的Golang示例,展示如何使用Toxiproxy模拟网络延迟:

package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/Shopify/toxiproxy/v2/client"
)

func main() {
	// 创建Toxiproxy客户端
	toxiproxyClient := client.NewClient("http://localhost:8474")

	// 创建代理
	proxy, err := toxiproxyClient.CreateProxy("test_redis", "localhost:26379", "localhost:6379")
	if err != nil {
		log.Fatal(err)
	}

	// 添加延迟toxic
	_, err = proxy.AddToxic("latency_downstream", "latency", "downstream", 1.0, client.Attributes{
		"latency": 1000, // 1000毫秒延迟
		"jitter":  100,  // 100毫秒抖动
	})
	if err != nil {
		log.Fatal(err)
	}

	// 测试Redis连接
	start := time.Now()
	resp, err := http.Get("http://localhost:26379")
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	fmt.Printf("请求耗时: %v\n", time.Since(start))

	// 清理
	err = proxy.Delete()
	if err != nil {
		log.Fatal(err)
	}
}

核心概念

  1. 代理(Proxy):Toxiproxy在客户端和上游服务之间创建的TCP代理

    • name: 代理名称
    • listen: 监听地址
    • upstream: 上游服务地址
    • enabled: 是否启用
  2. Toxics(干扰器):应用于代理连接的干扰规则

    • 常见类型:latency(延迟)、bandwidth(带宽限制)、timeout(超时)等
    • 可以设置方向(upstream/downstream)和应用概率(toxicity)

常用Toxics

延迟(latency)

// 添加1000ms延迟 ±100ms抖动
_, err = proxy.AddToxic("latency", "latency", "downstream", 1.0, client.Attributes{
    "latency": 1000,
    "jitter": 100,
})

带宽限制(bandwidth)

// 限制带宽为100KB/s
_, err = proxy.AddToxic("slow_bandwidth", "bandwidth", "downstream", 1.0, client.Attributes{
    "rate": 100, // KB/s
})

超时(timeout)

// 设置1000ms后超时
_, err = proxy.AddToxic("timeout", "timeout", "downstream", 1.0, client.Attributes{
    "timeout": 1000,
})

HTTP API

Toxiproxy提供RESTful API管理代理和Toxics,主要端点包括:

  • GET /proxies - 列出所有代理
  • POST /proxies - 创建新代理
  • POST /proxies/{proxy}/toxics - 为代理添加Toxic
  • DELETE /proxies/{proxy} - 删除代理

测试示例

func TestRedisWithLatency(t *testing.T) {
    // 创建Toxiproxy客户端
    toxiproxyClient := client.NewClient("http://localhost:8474")
    
    // 创建Redis代理
    proxy, err := toxiproxyClient.CreateProxy("test_redis", "localhost:26379", "localhost:6379")
    if err != nil {
        t.Fatal(err)
    }
    defer proxy.Delete()
    
    // 添加延迟
    _, err = proxy.AddToxic("latency", "latency", "downstream", 1.0, client.Attributes{
        "latency": 1000,
    })
    if err != nil {
        t.Fatal(err)
    }
    
    // 测试Redis连接
    start := time.Now()
    conn, err := redis.Dial("tcp", "localhost:26379")
    if err != nil {
        t.Fatal(err)
    }
    defer conn.Close()
    
    if time.Since(start) < time.Second {
        t.Error("延迟未生效")
    }
}

Toxiproxy是验证应用程序弹性和容错能力的强大工具,特别适合在自动化测试中模拟各种网络异常情况。


更多关于golang自动化测试网络环境模拟代理插件toxiproxy的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang自动化测试网络环境模拟代理插件toxiproxy的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用Toxiproxy进行Golang网络环境模拟测试

Toxiproxy是一个强大的网络代理工具,专门用于模拟各种网络环境条件,非常适合在自动化测试中模拟网络故障、延迟、限制等情况。下面我将介绍如何在Golang项目中使用Toxiproxy进行网络环境模拟测试。

1. Toxiproxy简介

Toxiproxy提供以下主要功能:

  • 延迟注入
  • 带宽限制
  • 连接断开
  • 数据包丢弃
  • 超时模拟

2. 安装Toxiproxy

首先需要安装Toxiproxy服务:

# 使用Docker安装
docker pull ghcr.io/shopify/toxiproxy:latest
docker run -d -p 8474:8474 -p 9000-9100:9000-9100 ghcr.io/shopify/toxiproxy

3. Golang客户端库

安装Golang的Toxiproxy客户端库:

go get github.com/Shopify/toxiproxy/v2/client

4. 基本使用示例

4.1 创建代理

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/Shopify/toxiproxy/v2/client"
)

func main() {
	// 创建Toxiproxy客户端
	toxiproxyClient := client.NewClient("localhost:8474")

	// 创建一个代理,将本地9000端口转发到example.com的80端口
	proxy, err := toxiproxyClient.CreateProxy("web", "localhost:9000", "example.com:80")
	if err != nil {
		log.Fatal(err)
	}

	// 添加1000ms的延迟和10%的数据包丢失
	_, err = proxy.AddToxic("latency_down", "latency", "downstream", 1.0, map[string]interface{}{
		"latency": 1000,
		"jitter":  100,
	})
	if err != nil {
		log.Fatal(err)
	}

	_, err = proxy.AddToxic("loss_down", "limit_data", "downstream", 1.0, map[string]interface{}{
		"bytes": 1000, // 每1000字节后断开连接
	})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Proxy created with latency and packet loss")
	time.Sleep(10 * time.Minute) // 保持代理运行
}

4.2 测试HTTP请求

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"github.com/Shopify/toxiproxy/v2/client"
)

func testHTTPRequest() {
	// 注意我们使用的是Toxiproxy创建的代理端口(9000)而不是直接连接目标
	resp, err := http.Get("http://localhost:9000")
	if err != nil {
		log.Printf("HTTP request failed: %v", err)
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Printf("Failed to read response: %v", err)
		return
	}

	fmt.Printf("Response status: %s, Body length: %d\n", resp.Status, len(body))
}

func main() {
	toxiproxyClient := client.NewClient("localhost:8474")

	// 创建代理
	proxy, err := toxiproxyClient.CreateProxy("http_test", "localhost:9000", "httpbin.org:80")
	if err != nil {
		log.Fatal(err)
	}

	// 测试正常请求
	fmt.Println("Testing normal request...")
	testHTTPRequest()

	// 添加延迟
	fmt.Println("\nAdding 2s latency...")
	_, err = proxy.AddToxic("latency", "latency", "downstream", 1.0, map[string]interface{}{
		"latency": 2000,
	})
	if err != nil {
		log.Fatal(err)
	}
	testHTTPRequest()

	// 添加超时
	fmt.Println("\nAdding timeout...")
	_, err = proxy.AddToxic("timeout", "timeout", "downstream", 1.0, map[string]interface{}{
		"timeout": 1000,
	})
	if err != nil {
		log.Fatal(err)
	}
	testHTTPRequest()

	// 重置所有toxics
	fmt.Println("\nResetting all toxics...")
	err = proxy.ResetState()
	if err != nil {
		log.Fatal(err)
	}
	testHTTPRequest()
}

5. 在单元测试中使用Toxiproxy

下面是一个完整的单元测试示例,展示如何在测试中模拟网络问题:

package main

import (
	"net/http"
	"testing"
	"time"

	"github.com/Shopify/toxiproxy/v2/client"
	"github.com/stretchr/testify/assert"
)

func TestHttpClientWithToxiproxy(t *testing.T) {
	// 初始化Toxiproxy客户端
	toxiproxyClient := client.NewClient("localhost:8474")

	// 创建代理
	proxy, err := toxiproxyClient.CreateProxy("test_proxy", "localhost:9001", "httpbin.org:80")
	assert.NoError(t, err)
	defer proxy.Delete() // 测试结束后删除代理

	// 测试用例1: 正常请求
	t.Run("normal request", func(t *testing.T) {
		client := http.Client{Timeout: 5 * time.Second}
		resp, err := client.Get("http://localhost:9001/get")
		assert.NoError(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode)
	})

	// 测试用例2: 带延迟的请求
	t.Run("request with latency", func(t *testing.T) {
		// 添加200ms延迟
		_, err := proxy.AddToxic("latency", "latency", "downstream", 1.0, map[string]interface{}{
			"latency": 200,
		})
		assert.NoError(t, err)

		start := time.Now()
		client := http.Client{Timeout: 1 * time.Second}
		_, err = client.Get("http://localhost:9001/get")
		assert.NoError(t, err)
		assert.GreaterOrEqual(t, time.Since(start).Milliseconds(), int64(200))
	})

	// 测试用例3: 模拟超时
	t.Run("request timeout", func(t *testing.T) {
		// 添加3秒延迟,但客户端只等待1秒
		_, err := proxy.AddToxic("high_latency", "latency", "downstream", 1.0, map[string]interface{}{
			"latency": 3000,
		})
		assert.NoError(t, err)

		client := http.Client{Timeout: 1 * time.Second}
		_, err = client.Get("http://localhost:9001/get")
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "context deadline exceeded")
	})

	// 重置代理状态
	err = proxy.ResetState()
	assert.NoError(t, err)
}

6. 高级用法

6.1 模拟带宽限制

// 限制下游带宽为100KB/s
_, err = proxy.AddToxic("bandwidth", "bandwidth", "downstream", 1.0, map[string]interface{}{
	"rate": 100 * 1024, // 字节/秒
})

6.2 模拟连接断开

// 模拟50%的连接断开
_, err = proxy.AddToxic("slicer", "slicer", "downstream", 1.0, map[string]interface{}{
	"average_size": 1024,
	"size_variation": 512,
	"delay": 100,
})

7. 最佳实践

  1. 测试隔离:每个测试用例应该创建自己的代理,避免相互干扰
  2. 资源清理:测试完成后删除代理和toxics
  3. 组合使用:可以组合多种toxics模拟复杂网络环境
  4. 真实场景:根据实际用户网络条件设计测试场景

Toxiproxy为Golang应用的网络可靠性测试提供了强大工具,能够帮助开发者发现和修复各种网络边界条件下的问题。

回到顶部