Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/santhosh-tekuri/fnet
programmable hosts, firewall, bandwidth to test network failures in unit testing
https://github.com/santhosh-tekuri/fnet
bandwidth clusters golang network-failures split-brain testing
Last synced: 27 days ago
JSON representation
programmable hosts, firewall, bandwidth to test network failures in unit testing
- Host: GitHub
- URL: https://github.com/santhosh-tekuri/fnet
- Owner: santhosh-tekuri
- License: apache-2.0
- Created: 2019-02-13T09:20:23.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2019-04-09T08:28:04.000Z (over 5 years ago)
- Last Synced: 2024-10-18T11:37:34.176Z (3 months ago)
- Topics: bandwidth, clusters, golang, network-failures, split-brain, testing
- Language: Go
- Homepage:
- Size: 175 KB
- Stars: 1
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
#fnet
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![GoDoc](https://godoc.org/github.com/santhosh-tekuri/fnet?status.svg)](https://godoc.org/github.com/santhosh-tekuri/fnet)
[![Go Report Card](https://goreportcard.com/badge/github.com/santhosh-tekuri/fnet)](https://goreportcard.com/report/github.com/santhosh-tekuri/fnet)
[![Build Status](https://travis-ci.org/santhosh-tekuri/fnet.svg?branch=master)](https://travis-ci.org/santhosh-tekuri/fnet)
[![codecov.io](https://codecov.io/github/santhosh-tekuri/fnet/coverage.svg?branch=master)](https://codecov.io/github/santhosh-tekuri/fnet?branch=master)Package fnet provides programmable firewall, bandwidth to test
network failures in unit testing.This package (fnet stands for fakenet) is intended for use in unit-testing network related failures.
Your library does not need any dependency on this package for this. only your
tests need this package as dependency.This package simply wraps `net.Listen`, `net.Dial`, `net.Conn` implementation on
`tcp:localhost`. It enforces firewall/bandwidth before delegating to actual
implementationSome minimal changes needs to be done in your library for this. Consider following
simple library code, to demonstrate the changes:~~~go
package myapptype Server struct{
HostPort string
....
}func (s *Server) launch() {
lr, err := net.Listen("tcp", s.HostPort)
...
}type Client struct{
HostPort string
...
}func (c *client) sendReq(req string) error {
conn, err := net.Dial("tcp", c.HostPort)
...
}
~~~You have to mock `net.Listen`, `net.Dial` in your code. For this introduce transport interface as shown below:
~~~go
package myapptype listenFn func(network, address string) (net.Listener, error)
type dialFn func(network, address string) (net.Conn, error)type Server struct{
HostPort string
listenFn listenFn // intialize to net.Listen
....
}func (s *Server) launch() {
lr, err := s.listenFn("tcp", s.HostPort)
...
}type Client struct{
HostPort string
dialFn dialFn // initialize to net.Dial
...
}func (c *client) sendReq(req string) error {
conn, err := c.dialFn("tcp", c.HostPort)
...
}// unit test code ---------------------
func TestServer(t *testing.T) {
// create network of 3 hosts
nw := fnet.New()
earth, mars, venus := nw.Host("earth"), nw.Host("mars"), nw.Host("venus")s1 := &Server{HostPort: "earth:80", listenFn: earth.Listen} // server1 running on earth
s2 := &Server{HostPort: "mars:80", listenFn: mars.Listen} // server2 running on mars
c := &Client{Servers: []{"earth:80", "mars:80"}, dialFn: venus.Dial} // client is running on venus// make s1 unreachable to client
nw.SetFirewall(fnet.Split([]string{"earth"}, fnet.AllowAll))
if reply, err := c.SendReq("hello"); err!=nil {
t.Fatal("expected to connect s2")
}// now make s2 unreachable to client, but not s1
nw.SetFirewall(fnet.Split([]string{"mars"}, fnet.AllowAll))
if reply, err := c.SendReq("hello"); err!=nil {
t.Fatal("expected to connect s1")
}
}
~~~
You can mock `net.Listen`, `net.Dial` and `net.DialTimeout` using this package as shown aboveNow you can various network failures as shown above using `fnet.Firewall` `fnet.Bandwidth`
## Firewalls
This package provides 3 implementations of firewall:
### AllowAll:
This does not block any network traffic.
This is the default firewall set on newly created network.### AllowSelf:
This blocks traffic between distinct hosts.
Note that traffic within the host is allowed.
Consider network with hosts m1, m2, m3 and m4,
AllowSelf creates 4 network partitions: m1 | m2 | m3 | m4### Split:
This implements network partioning. Mutiple partitions
can be defined by chaining. See example below:
~~~go
// Consider network with hosts m1, m2, m3, m4, m5 and m6// 2 partitions: m1 m2 | m3 m4 m5 m6
firewall := fnet.Split([]string{"m1", "m2"}, fnet.AllowAll)// 3 partitions: m1 m2 | m3 m4 | m5 m6
firewall := fnet.Split([]string{"m1", "m2"}, fnet.AllowAll)
firewall = fnet.Split([]string{"m3", "m4"}, firewall) // chaining
~~~
You can create your own firewall implementation if needed. It is simple single method interface:
~~~go
type Firewall interface {
Allow(host1, host2 string) bool
}
~~~## Bandwidth
to set bandwidth between two hosts:
~~~go
nw := fnet.New()
earth, mars := nw.Host("earth"), nw.Host("mars")
nw.SetBandwidth("earth", "mars", fnet.Bandwidth(10*1024*1024)) // 10MB per second between earth and mars// to revert
nw.SetBandwidth("earth", "mars", fnet.NoLimit)
~~~