8000 fix: pr71 by jesusprubio · Pull Request #80 · jesusprubio/up · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix: pr71 #80

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

Merged
merged 1 commit into from
Apr 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ name: CI

on:
push:
branches: main
tags: v*
branches: [main]
tags: [v*]
pull_request:

jobs:
Expand All @@ -16,7 +16,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: "1.23.2"
go-version: "1.24.2"
- name: Install Task
uses: arduino/setup-task@v2
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: "1.23.2"
go-version: "1.24.2"
- name: Release
uses: goreleaser/goreleaser-action@v6
env:
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ task build

## Release

TODO(#32)
We use [GoReleaser](https://goreleaser.com/) and GitHub workflows to automate
the binary publishing process. Setup files:

- [GoReleaser](./.goreleaser.yml)
- [GitHub Workflows](./.github/workflows/release.yml)
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ against a randomly selected [public server](internal/servers.go) for each one.

```sh
up
up -p http
up -p http -c 3
up -p http -tg example.com
cat testdata/stdin-urls.txt | go run . -p http
```

[doc-img]: https://pkg.go.dev/badge/github.com/jesusprubio/up
Expand Down
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ tasks:

test:
summary: "Run tests"
cmd: go test -v ./...
cmd: go test ./...
32 changes: 0 additions & 32 deletions examples/tcp.go

This file was deleted.

2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/jesusprubio/up

go 1.22.4
go 1.23.5

require github.com/fatih/color v1.18.0

Expand Down
29 changes: 26 additions & 3 deletions internal/options.go
Original file line number Diff line number Diff line chang 6D47 e
Expand Up @@ -2,15 +2,20 @@
package internal

import (
"errors"
"flag"
"time"
)

const targetDesc = "Protocol is required because the format is dependent: URL for HTTP, host:port for TCP, domain for DNS"

// Options are the flags supported by the command line application.
type Options struct {
// Input flags.
// Protocol to use. Example: 'http'.
Protocol string
// Where to point the probe.
// URL (HTTP), host/port string (TCP) or domain (DNS).
Target string
// Number of iterations. Zero means infinite.
Count uint
// Time to wait for a response.
Expand All @@ -32,11 +37,14 @@ type Options struct {
Debug bool
// Show app documentation.
Help bool
// Disable stardard input target reading.
NoStdin bool
}

// Parse fulfills the command line flags provided by the user.
func (opts *Options) Parse() {
func (opts *Options) Parse() error {
flag.StringVar(&opts.Protocol, "p", "", "Test only one protocol")
flag.StringVar(&opts.Target, "tg", "", targetDesc)
flag.UintVar(&opts.Count, "c", 0, "Number of iterations")
flag.DurationVar(
&opts.Timeout, "t", 5*time.Second, "Time to wait for a response",
Expand All @@ -51,7 +59,22 @@ func (opts *Options) Parse() {
flag.BoolVar(&opts.JSONOutput, "j", false, "Output in JSON format")
flag.BoolVar(&opts.GrepOutput, "g", false, "Output in grepable format")
flag.BoolVar(&opts.NoColor, "nc", false, "Disable color output")
flag.BoolVar(&opts.Debug, "dbg", false, "Verbose output")
flag.BoolVar(&opts.Debug, "vv", false, "Verbose output")
flag.BoolVar(&opts.Help, "h", false, "Show app documentation")
flag.BoolVar(
&opts.NoStdin,
"nstd",
false,
"Disable standard input target reading",
)
flag.Parse()
return opts.validate()
}

// Ensures the setup is correct.
func (opts *Options) validate() error {
if opts.Target != "" && opts.Protocol == "" {
return errors.New("protocol is required if target is set")
}
return nil
}
108 changes: 38 additions & 70 deletions internal/probe.go
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import (
"time"
)

// Probe is an experiment to measure the connectivity of a network using
// different protocols and public servers.
// Probe is an experiment to measure the connectivity of a network.
type Probe struct {
// Protocols to use.
Protocols []Protocol
// Protocol to use.
Proto Protocol
// Number of iterations. Zero means infinite.
Count uint
// Delay between requests.
Expand All @@ -20,14 +19,15 @@ type Probe struct {
Logger *slog.Logger
// Channel to send back partial results.
ReportCh chan *Report
// URLs (HTTP), host/port strings (TCP) or domains (DNS).
Input []string
// Optional. Where to point the probe.
// URL (HTTP), host/port string (TCP) or domain (DNS).
Target string
}

// Ensures the probe setup is correct.
func (p Probe) validate() error {
if p.Protocols == nil {
return newErrorReqProp("Protocols")
if p.Proto == nil {
return newErrorReqProp("Proto")
}
// 'Delay' could be zero.
if p.Logger == nil {
Expand Down Expand Up @@ -58,71 +58,39 @@ func (p Probe) Do(ctx context.Context) error {
for {
select {
case <-ctx.Done():
p.Logger.Debug(
"Context cancelled between iterations",
"count", count,
)
p.Logger.Debug("Context cancelled", "count", count)
return nil
default:
p.Logger.Debug("New iteration", "count", count)
for _, proto := range p.Protocols {
select {
case <-ctx.Done():
p.Logger.Debug(
"Context cancelled between protocols",
"count", count, "protocol", proto,
)
return nil
default:
start := time.Now()
p.Logger.Debug(
"New protocol", "count", count, "protocol", proto,
)
if len(p.Input) == 0 {
// Probe default list of urls
rhost, extra, err := proto.Probe("")
report := Report{
ProtocolID: proto.String(),
Time: time.Since(start),
Error: err,
RHost: rhost,
Extra: extra,
}
p.Logger.Debug(
"Sending report back",
"count", count, "report", report,
)
p.ReportCh <- &report
time.Sleep(p.Delay)
continue
}

// iterate over User provided inputs
for _, addr := range p.Input {
rhost, extra, err := proto.Probe(addr)
report := Report{
ProtocolID: proto.String(),
Time: time.Since(start),
Error: err,
RHost: rhost,
Extra: extra,
}
p.Logger.Debug(
"Sending report back for address",
"count", count, "address", addr, "report", report,
)
p.ReportCh <- &report
time.Sleep(p.Delay)
}
}
time.Sleep(p.Delay)
p.Logger.Debug(
"New iteration",
"count",
count,
"protocol",
p.Proto,
"target",
p.Target,
)
start := time.Now()
target, extra, err := p.Proto.Probe(p.Target)
var errMsg string
if err != nil {
errMsg = err.Error()
}
report := Report{
ProtocolID: p.Proto.String(),
Time: time.Since(start),
Error: errMsg,
Target: target,
Extra: extra,
}
p.Logger.Debug("Sending report back", "report", report)
p.ReportCh <- &report
time.Sleep(p.Delay)
count++
if p.Count > 0 && count >= p.Count {
p.Logger.Debug("Count limit reached", "count", count)
return nil
}
}
p.Logger.Debug("Iteration finished", "count", count, "p.Count", p.Count)
count++
if count == p.Count {
p.Logger.Debug("Count limit reached", "count", count)
return nil
}
}
}
39 changes: 19 additions & 20 deletions internal/probe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,35 @@ func (p *testProtocol) Probe(target string) (string, string, error) {
}

func TestProbeValidate(t *testing.T) {
protocols := []Protocol{&testProtocol{}}
proto := &testProtocol{}
logger := slog.Default()
reportCh := make(chan *Report)
defer close(reportCh)
t.Run("returns nil with valid setup", func(t *testing.T) {
reportCh := make(chan *Report)
defer close(reportCh)
p := Probe{
Protocols: protocols, Logger: slog.Default(), ReportCh: reportCh,
}
p := Probe{Proto: proto, Logger: logger, ReportCh: reportCh}
err := p.validate()
if err != nil {
t.Fatalf("got %q, want nil", err)
}
})
t.Run("returns an error if 'Protocols' is nil", func(t *testing.T) {
t.Run("returns an error if 'Proto' is nil", func(t *testing.T) {
p := Probe{}
err := p.validate()
want := "required property: Protocols"
want := "required property: Proto"
if err.Error() != want {
t.Fatalf("got %q, want %q", err, want)
}
})
t.Run("returns an error if 'Logger' is nil", func(t *testing.T) {
p := Probe{Protocols: protocols}
p := Probe{Proto: proto}
err := p.validate()
want := "required property: Logger"
if err.Error() != want {
t.Fatalf("got %q, want %q", err, want)
}
})
t.Run("returns an error if 'ReportCh' is nil", func(t *testing.T) {
p := Probe{Protocols: protocols, Logger: slog.Default()}
p := Probe{Proto: proto, Logger: logger}
err := p.validate()
want := "required property: ReportCh"
if err.Error() != want {
Expand All @@ -60,29 +59,29 @@ func TestProbeDo(t *testing.T) {
t.Run("returns an error if the setup is invalid", func(t *testing.T) {
p := Probe{}
err := p.Do(context.Background())
want := "invalid setup: required property: Protocols"
want := "invalid setup: required property: Proto"
if err.Error() != want {
t.Fatalf("got %q, want %q", err, want)
}
})
protocols := []Protocol{&testProtocol{}}
protocol := &testProtocol{}
t.Run("sends back the report in the channel", func(t *testing.T) {
reportCh := make(chan *Report)
defer close(reportCh)
p := Probe{
Protocols: protocols,
Count: 2,
Logger: slog.Default(),
ReportCh: reportCh,
Proto: &testProtocol{},
Count: 2,
Logger: slog.Default(),
ReportCh: reportCh,
}
protoID := protocols[0].String()
protoID := protocol.String()
go func(t *testing.T) {
for report := range p.ReportCh {
if report.ProtocolID != protoID {
t.Errorf("got %q, want %q", report.ProtocolID, protoID)
}
if report.RHost != testHostPort {
t.Errorf("got %q, want %q", report.RHost, testHostPort)
if report.Target != testHostPort {
t.Errorf("got %q, want %q", report.Target, testHostPort)
}
if report.Time == 0 {
t.Errorf("got %q, want > 0", report.Time)
Expand All @@ -101,7 +100,7 @@ func TestProbeDo(t *testing.T) {
reportCh := make(chan *Report)
defer close(reportCh)
p := Probe{
Protocols: protocols, Logger: slog.Default(), ReportCh: reportCh,
Proto: protocol, Logger: slog.Default(), ReportCh: reportCh,
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
Expand Down
Loading
0