Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc: explain how to write ooni nettests #506

Closed
wants to merge 68 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
a3d214c
netx: carry over changes from plan B
bassosimone Sep 19, 2021
a4ac1a2
plan C
bassosimone Sep 20, 2021
e1de317
improve websteps prototype
bassosimone Sep 20, 2021
ac0ee0b
refactor: move websteps specific code outisde of measurex
bassosimone Sep 20, 2021
7304342
feat: from a single step to multiple steps
bassosimone Sep 20, 2021
2b33c25
feat: add oddity and holding logger
bassosimone Sep 20, 2021
7bda89e
forgot to commit oddity.go
bassosimone Sep 20, 2021
15da819
start doing some QA and fixing bugs
bassosimone Sep 20, 2021
f1db43a
heavy refactoring
bassosimone Sep 20, 2021
82289ed
support parallel HTTPEndpoint measurements
bassosimone Sep 21, 2021
be77fd7
identify sharing constraints and fix
bassosimone Sep 21, 2021
1272aa2
allow for parallel dns resolutions
bassosimone Sep 21, 2021
df68e46
allow running automatic "parallel" TH queries
bassosimone Sep 21, 2021
9a25631
at last add code for parsing a URL
bassosimone Sep 21, 2021
e77020f
compute all the redirections
bassosimone Sep 21, 2021
f922ec5
implement following redirections
bassosimone Sep 21, 2021
97519ae
fix: pass around the measurement ID
bassosimone Sep 21, 2021
d163f46
also archival now is okay
bassosimone Sep 21, 2021
57d9f5d
start to commit the tutorials
bassosimone Sep 21, 2021
91b0ae3
ignore jafar binary
bassosimone Sep 21, 2021
6dd602a
teach miniooni to run websteps
bassosimone Sep 21, 2021
4b8f005
fix: compute measurement runtime in a better way
bassosimone Sep 21, 2021
c9f88cc
feat: add runtime metrics before experimental run
bassosimone Sep 21, 2021
9e11026
fix: improve UX related to logging
bassosimone Sep 21, 2021
0ec2e7a
more clarity
bassosimone Sep 21, 2021
a4b1cfa
improve logging after feedback and add bandwidth monitoring
bassosimone Sep 21, 2021
74e8fa5
fix: also save elapsed time
bassosimone Sep 22, 2021
a431a0d
implement and expose new websteps test helper
bassosimone Sep 22, 2021
2a30471
make sure we also parse alt-svc
bassosimone Sep 22, 2021
a75f50f
document each file's content and rationale
bassosimone Sep 22, 2021
00258d2
heavy refactoring to simplify plan C
bassosimone Sep 22, 2021
ab48a8b
start refactoring to simplify the TH
bassosimone Sep 22, 2021
02bb05a
continue preparing for reducing th code complexity
bassosimone Sep 22, 2021
80681e5
simplify archival by making dnsx data format equal to archival
bassosimone Sep 22, 2021
ad0a3cf
now also http uses the ooni data format
bassosimone Sep 23, 2021
cbcfb28
finish converting to ooni data format
bassosimone Sep 23, 2021
ca728c3
adjusted TH to use most abstract measurex
bassosimone Sep 23, 2021
19e45d5
make th work and fix a bunch of bugs
bassosimone Sep 23, 2021
a2c5628
some readability fixes
bassosimone Sep 23, 2021
05e38f4
continue improving docs
bassosimone Sep 23, 2021
e155a08
the tutorials are now ready
bassosimone Sep 24, 2021
eccaa47
Minor edits to chapter01
hellais Sep 24, 2021
f83c5a8
Minor edits to chapter02
hellais Sep 24, 2021
b82c207
Merge branch 'master' into planc
bassosimone Sep 27, 2021
cb30de8
netxlite: start documenting new factories
bassosimone Sep 27, 2021
85abfb3
Merge branch 'master' into planc
bassosimone Sep 27, 2021
0676179
transport: do not mutate outgoing request
bassosimone Sep 27, 2021
c4b45c3
Merge branch 'master' into planc
bassosimone Sep 27, 2021
90234cc
typo
bassosimone Sep 27, 2021
adfc7e2
Merge branch 'master' into planc
bassosimone Sep 27, 2021
276d500
Merge branch 'master' into planc
bassosimone Sep 27, 2021
643fc2b
Merge branch 'master' into planc
bassosimone Sep 27, 2021
1ef81f4
Merge branch 'master' into planc
bassosimone Sep 27, 2021
633befd
remove LookupHostWithoutRetry
bassosimone Sep 27, 2021
45dc835
Rename to LookupHTTPS (simpler, shorter name)
bassosimone Sep 27, 2021
2b4f878
fix: simplify LookupHTTPS API
bassosimone Sep 27, 2021
fef294b
Merge branch 'master' into planc
bassosimone Sep 27, 2021
34dc086
Merge branch 'master' into planc
bassosimone Sep 28, 2021
d46f1a7
refactor(meaurex,webstepsx): use new netxlite API
bassosimone Sep 28, 2021
5db714e
Merge branch 'master' into planc
bassosimone Sep 29, 2021
8b0071a
measurex: make th interface more practical
bassosimone Sep 29, 2021
cfbc143
Merge branch 'master' into planc
bassosimone Sep 29, 2021
ffc6db1
Merge branch 'master' into planc
bassosimone Sep 29, 2021
5597d4e
Merge branch 'master' into planc
bassosimone Sep 29, 2021
f8209df
Merge branch 'master' into planc
bassosimone Sep 29, 2021
cc3a78e
fix wrong diff with master
bassosimone Sep 29, 2021
1744cd0
fix(webstepsx): point code to roaming th
bassosimone Sep 29, 2021
72ef21d
Merge branch 'master' into planc
bassosimone Sep 30, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
.DS_Store
/*.asc
/*.deb
/*.jsonl
/*.tar.gz
/*.zip
/apitool
/apitool.exe
/*.asc
/bandwidth.json
/coverage.cov
/*.deb
/debops-ci
.DS_Store
/*.jsonl
/jafar
/jafar.exe
/miniooni
/miniooni.exe
/oohelper
/oohelper.exe
/oohelperd
/oohelperd.exe
/oohelper.exe
/ooniprobe
/ooniprobe.exe
/ooniprobe_checksums.txt
/ooniprobe_checksums.txt.asc
/ooniprobe.exe
/probe-cli.cov
/ptxclient
/ptxclient.exe
/*.tar.gz
/testdata/gotmp
/*.zip
9 changes: 9 additions & 0 deletions internal/cmd/miniooni/libminiooni.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import (
"github.com/ooni/probe-cli/v3/internal/engine/model"
"github.com/ooni/probe-cli/v3/internal/humanize"
"github.com/ooni/probe-cli/v3/internal/kvstore"
"github.com/ooni/probe-cli/v3/internal/netxlite"
"github.com/ooni/probe-cli/v3/internal/version"
"github.com/pborman/getopt/v2"
)

// Options contains the options you can set from the CLI.
type Options struct {
Annotations []string
BWMon string
ExtraOptions []string
HomeDir string
Inputs []string
Expand Down Expand Up @@ -61,6 +63,9 @@ func init() {
getopt.FlagLong(
&globalOptions.Annotations, "annotation", 'A', "Add annotaton", "KEY=VALUE",
)
getopt.FlagLong(
&globalOptions.BWMon, "bwmon", 0, "Monitor bandwidth and save results to file", "PATH",
)
getopt.FlagLong(
&globalOptions.ExtraOptions, "option", 'O',
"Pass an option to the experiment", "KEY=VALUE",
Expand Down Expand Up @@ -295,6 +300,10 @@ func MainWithConfiguration(experimentName string, currentOptions Options) {

ctx := context.Background()

if currentOptions.BWMon != "" {
netxlite.MonitorBandwidth(ctx, currentOptions.BWMon)
}

extraOptions := mustMakeMap(currentOptions.ExtraOptions)
annotations := mustMakeMap(currentOptions.Annotations)

Expand Down
187 changes: 187 additions & 0 deletions internal/netxlite/bwmon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package netxlite

import (
"context"
"encoding/json"
"net"
"os"
"sync"
"time"

"github.com/ooni/probe-cli/v3/internal/atomicx"
"github.com/ooni/probe-cli/v3/internal/netxlite/quicx"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)

// bandwidthStats contains bandwidth stats.
type bandwidthStats struct {
// Timestamp is the timestamp when we saved this snapshot.
Timestamp time.Time

// Elapsed is the elapsed time since the beginning.
Elapsed time.Duration

// Read is the number of bytes read using Read.
Read int64

// ReadFrom is the number of bytes read using ReadFrom.
ReadFrom int64

// Write is the number of bytes written using Write.
Write int64

// WriteTo is the number of bytes written using WriteTo.
WriteTo int64
}

// bandwidthMonitor monitors the bandwidth usage.
type bandwidthMonitor struct {
begin time.Time
enabled *atomicx.Int64
stats bandwidthStats
mu sync.Mutex
}

// MonitorBandwidth configures bandwidth monitoring. The filename
// argument is the name of the file where to write snapshots. By
// default bandwidth monitoring is disabled and you only enable it
// by calling this function once in your main function.
func MonitorBandwidth(ctx context.Context, filename string) {
bwmonitor.enabled.Add(1)
go bwmonitor.measure(ctx, filename)
}

// measure performs periodic measurements.
func (bwmon *bandwidthMonitor) measure(ctx context.Context, filename string) {
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case t := <-ticker.C:
bwmon.saveSnapshot(t, filename)
case <-ctx.Done():
return
}
}
}

// saveSnapshot appends the snapshot to the snapshots file.
func (bwmon *bandwidthMonitor) saveSnapshot(t time.Time, filename string) {
bwmon.mu.Lock()
bwmon.stats.Timestamp = t
bwmon.stats.Elapsed = t.Sub(bwmon.begin)
data, err := json.Marshal(bwmon.stats)
bwmon.stats = bandwidthStats{}
bwmon.mu.Unlock()
data = append(data, '\n')
runtimex.PanicOnError(err, "json.Marshal failed")
const flags = os.O_APPEND | os.O_CREATE | os.O_WRONLY
filep, err := os.OpenFile(filename, flags, 0644)
if err != nil {
return
}
defer filep.Close()
if _, err := filep.Write(data); err != nil {
filep.Close()
return
}
}

// MaybeWrapConn possibly wraps a net.Conn to add bandwidth monitoring. If there is
// an error this function immediately returns an error. Bandwidth monitoring is
// disabled by default, but can be enabled when required.
func (bwmon *bandwidthMonitor) MaybeWrapConn(conn net.Conn, err error) (net.Conn, error) {
if bwmon.enabled.Load() == 0 {
return conn, err
}
if err != nil {
return nil, err
}
return &bwmonConn{Conn: conn, bwmon: bwmon}, nil
}

// OnRead measures the results of Conn.Read.
func (bwmon *bandwidthMonitor) OnRead(count int, err error) (int, error) {
bwmon.mu.Lock()
bwmon.stats.Read += int64(count)
bwmon.mu.Unlock()
return count, err
}

// OnWrite measures the results of Conn.Write.
func (bwmon *bandwidthMonitor) OnWrite(count int, err error) (int, error) {
bwmon.mu.Lock()
bwmon.stats.Write += int64(count)
bwmon.mu.Unlock()
return count, err
}

// OnWriteTo measures the results of UDPLikeConn.WriteTo.
func (bwmon *bandwidthMonitor) OnWriteTo(count int, err error) (int, error) {
bwmon.mu.Lock()
bwmon.stats.WriteTo += int64(count)
bwmon.mu.Unlock()
return count, err
}

// OnReadFrom measures the results of UDPLikeConn.ReadFrom.
func (bwmon *bandwidthMonitor) OnReadFrom(
count int, addr net.Addr, err error) (int, net.Addr, error) {
bwmon.mu.Lock()
bwmon.stats.ReadFrom += int64(count)
bwmon.mu.Unlock()
return count, addr, err
}

// bwmonConn wraps a net.Conn to add bandwidth monitoring.
type bwmonConn struct {
net.Conn
bwmon *bandwidthMonitor
}

// Read implements net.Conn.Read.
func (c *bwmonConn) Read(b []byte) (int, error) {
return c.bwmon.OnRead(c.Conn.Read(b))
}

// Read implements net.Conn.Read.
func (c *bwmonConn) Write(b []byte) (int, error) {
return c.bwmon.OnWrite(c.Conn.Write(b))
}

// MaybeWrapUDPLikeConn possibly wraps a quicx.UDPLikeConn to add bandwidth
// monitoring. If there is an error this function immediately returns an
// error. Bandwidth monitoring is disabled by default, but can be
// enabled when required.
func (bwmon *bandwidthMonitor) MaybeWrapUDPLikeConn(
conn quicx.UDPLikeConn, err error) (quicx.UDPLikeConn, error) {
if bwmon.enabled.Load() == 0 {
return conn, err
}
if err != nil {
return nil, err
}
return &bwmonUDPLikeConn{UDPLikeConn: conn, bwmon: bwmon}, nil
}

// bwmonUDPLikeConn wraps a quicx.UDPLikeConn to add bandwidth monitoring.
type bwmonUDPLikeConn struct {
quicx.UDPLikeConn
bwmon *bandwidthMonitor
}

// WriteTo implements quicx.UDPLikeConn.WriteTo.
func (c *bwmonUDPLikeConn) WriteTo(p []byte, addr net.Addr) (int, error) {
return c.bwmon.OnWriteTo(c.UDPLikeConn.WriteTo(p, addr))
}

// ReadFrom implements quicx.UDPLikeConn.ReadFrom.
func (c *bwmonUDPLikeConn) ReadFrom(b []byte) (int, net.Addr, error) {
return c.bwmon.OnReadFrom(c.UDPLikeConn.ReadFrom(b))
}

// bwmonitor is the bandwidth monitor singleton
var bwmonitor = &bandwidthMonitor{
begin: time.Now(),
enabled: &atomicx.Int64{},
}
3 changes: 2 additions & 1 deletion internal/netxlite/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ func (d *dialerSystem) newUnderlyingDialer() *net.Dialer {
}

func (d *dialerSystem) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
return d.newUnderlyingDialer().DialContext(ctx, network, address)
return bwmonitor.MaybeWrapConn(
d.newUnderlyingDialer().DialContext(ctx, network, address))
}

func (d *dialerSystem) CloseIdleConnections() {
Expand Down
2 changes: 1 addition & 1 deletion internal/netxlite/quic.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var _ QUICListener = &quicListenerStdlib{}

// Listen implements QUICListener.Listen.
func (qls *quicListenerStdlib) Listen(addr *net.UDPAddr) (UDPLikeConn, error) {
return net.ListenUDP("udp", addr)
return bwmonitor.MaybeWrapUDPLikeConn(net.ListenUDP("udp", addr))
}

// QUICDialer dials QUIC sessions.
Expand Down