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

feat: history command #97

Merged
merged 7 commits into from
Mar 27, 2024
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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ Measurement Commands:
Additional Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
history Show the history of your measurements in your current session
install-probe Join the community powered Globalping platform by running a Docker container.
version Print the version number of Globalping CLI

Expand Down Expand Up @@ -307,6 +308,24 @@ Madrid, ES, EU, EDGOO NETWORKS LLC (AS47787) | 22 | 0.00% | 0.24
^C
```

#### History

You can view the history of your measurements by running the `history` command.

```bash
globalping history
1 | 2024-03-27 11:56:46 | ping google.com
> https://www.jsdelivr.com/globalping?measurement=itcR65tYCqbouXib
- | 2024-03-27 11:57:01 | dns google.com from last
> https://www.jsdelivr.com/globalping?measurement=kWc5UBK9A6G4RUYM
2 | 2024-03-27 11:57:20 | traceroute google.com from New York --limit 2
> https://www.jsdelivr.com/globalping?measurement=Yz7A1UifUonZsC3C
3 | 2024-03-27 11:57:37 | mtr google.com from New York --limit 2
> https://www.jsdelivr.com/globalping?measurement=SX1NBgfDKiabM1vZ
4 | 2024-03-27 11:57:52 | http google.com from London,Belgium --limit 2 --method get --ci
> https://www.jsdelivr.com/globalping?measurement=eclwFSYX0zgU10Cs
```

#### Learn about available flags

Most commands have shared and unique flags. We recommend that you familiarize yourself with these so that you can run and automate your network tests in powerful ways.
Expand Down
33 changes: 21 additions & 12 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ import (
)

var (
ErrorNoPreviousMeasurements = errors.New("no previous measurements found")
ErrInvalidIndex = errors.New("invalid index")
ErrIndexOutOfRange = errors.New("index out of range")
ErrNoPreviousMeasurements = errors.New("no previous measurements found")
ErrInvalidIndex = errors.New("invalid index")
ErrIndexOutOfRange = errors.New("index out of range")
)
var (
saveIdToSessionErr = "failed to save measurement ID: %s"
readMeasuremetsErr = "failed to read previous measurements: %s"
)

var SESSION_PATH string
Expand Down Expand Up @@ -78,6 +82,7 @@ func (r *Root) getLocations() ([]globalping.Locations, error) {
if mId == "" {
mId = strings.TrimSpace(fromArr[0])
} else {
r.ctx.IsLocationFromSession = true
r.ctx.RecordToSession = false
}
return []globalping.Locations{{Magic: mId}}, nil
Expand Down Expand Up @@ -182,19 +187,19 @@ func getIdFromSession(index int) (string, error) {
f, err := os.Open(getMeasurementsPath())
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return "", ErrorNoPreviousMeasurements
return "", ErrNoPreviousMeasurements
}
return "", fmt.Errorf("failed to open previous measurements file: %s", err)
return "", fmt.Errorf(readMeasuremetsErr, err)
}
defer f.Close()
// Read ids from the end of the file
if index < 0 {
fStats, err := f.Stat()
if err != nil {
return "", fmt.Errorf("failed to read previous measurements: %s", err)
return "", fmt.Errorf(readMeasuremetsErr, err)
}
if fStats.Size() == 0 {
return "", ErrorNoPreviousMeasurements
return "", ErrNoPreviousMeasurements
}
scanner := backscanner.New(f, int(fStats.Size()-1)) // -1 to skip last newline
for {
Expand All @@ -204,7 +209,7 @@ func getIdFromSession(index int) (string, error) {
if err == io.EOF {
return "", ErrIndexOutOfRange
}
return "", fmt.Errorf("failed to read previous measurements: %s", err)
return "", fmt.Errorf(readMeasuremetsErr, err)
}
if index == 0 {
return string(b), nil
Expand Down Expand Up @@ -232,20 +237,20 @@ func saveIdToSession(id string) error {
if errors.Is(err, fs.ErrNotExist) {
err := os.Mkdir(getSessionPath(), 0755)
if err != nil {
return fmt.Errorf("failed to save measurement ID: %s", err)
return fmt.Errorf(saveIdToSessionErr, err)
}
} else {
return fmt.Errorf("failed to save measurement ID: %s", err)
return fmt.Errorf(saveIdToSessionErr, err)
}
}
f, err := os.OpenFile(getMeasurementsPath(), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return fmt.Errorf("failed to save measurement ID: %s", err)
return fmt.Errorf(saveIdToSessionErr, err)
}
defer f.Close()
_, err = f.WriteString(id + "\n")
if err != nil {
return fmt.Errorf("failed to save measurement ID: %s", err)
return fmt.Errorf(saveIdToSessionErr, err)
}
return nil
}
Expand Down Expand Up @@ -282,3 +287,7 @@ func getSessionId() string {
func getMeasurementsPath() string {
return filepath.Join(getSessionPath(), "measurements")
}

func getHistoryPath() string {
return filepath.Join(getSessionPath(), "history")
}
10 changes: 5 additions & 5 deletions cmd/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func Test_UpdateContext(t *testing.T) {
}

func test_updateContext_NoArg(t *testing.T) {
ctx := &view.Context{}
ctx := createDefaultContext("ping")
printer := view.NewPrinter(nil, nil, nil)
root := NewRoot(printer, ctx, nil, nil, nil, nil)

Expand All @@ -35,7 +35,7 @@ func test_updateContext_NoArg(t *testing.T) {
}

func test_updateContext_Country(t *testing.T) {
ctx := &view.Context{}
ctx := createDefaultContext("ping")
printer := view.NewPrinter(nil, nil, nil)
root := NewRoot(printer, ctx, nil, nil, nil, nil)

Expand All @@ -48,7 +48,7 @@ func test_updateContext_Country(t *testing.T) {

// Check if country with whitespace is parsed correctly
func test_updateContext_CountryWhitespace(t *testing.T) {
ctx := &view.Context{}
ctx := createDefaultContext("ping")
printer := view.NewPrinter(nil, nil, nil)
root := NewRoot(printer, ctx, nil, nil, nil, nil)

Expand All @@ -60,7 +60,7 @@ func test_updateContext_CountryWhitespace(t *testing.T) {
}

func test_updateContext_NoTarget(t *testing.T) {
ctx := &view.Context{}
ctx := createDefaultContext("ping")
printer := view.NewPrinter(nil, nil, nil)
root := NewRoot(printer, ctx, nil, nil, nil, nil)

Expand All @@ -73,7 +73,7 @@ func test_uodateContext_CIEnv(t *testing.T) {
t.Setenv("CI", "true")
defer t.Setenv("CI", oldCI)

ctx := &view.Context{}
ctx := createDefaultContext("ping")
printer := view.NewPrinter(nil, nil, nil)
root := NewRoot(printer, ctx, nil, nil, nil, nil)

Expand Down
19 changes: 13 additions & 6 deletions cmd/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"github.com/jsdelivr/globalping-cli/globalping"
"github.com/jsdelivr/globalping-cli/view"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -53,11 +54,11 @@ Using the dig format @resolver. For example:

// dns specific flags
flags := dnsCmd.Flags()
flags.StringVar(&r.ctx.Protocol, "protocol", "", "Specifies the protocol to use for the DNS query (TCP or UDP) (default \"udp\")")
flags.IntVar(&r.ctx.Port, "port", 0, "Send the query to a non-standard port on the server (default 53)")
flags.StringVar(&r.ctx.Resolver, "resolver", "", "Resolver is the hostname or IP address of the name server to use (default empty)")
flags.StringVar(&r.ctx.QueryType, "type", "", "Specifies the type of DNS query to perform (default \"A\")")
flags.BoolVar(&r.ctx.Trace, "trace", false, "Toggle tracing of the delegation path from the root name servers (default false)")
flags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "Specifies the protocol to use for the DNS query (TCP or UDP) (default \"udp\")")
flags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "Send the query to a non-standard port on the server (default 53)")
flags.StringVar(&r.ctx.Resolver, "resolver", r.ctx.Resolver, "Resolver is the hostname or IP address of the name server to use (default empty)")
flags.StringVar(&r.ctx.QueryType, "type", r.ctx.QueryType, "Specifies the type of DNS query to perform (default \"A\")")
flags.BoolVar(&r.ctx.Trace, "trace", r.ctx.Trace, "Toggle tracing of the delegation path from the root name servers (default false)")

r.Cmd.AddCommand(dnsCmd)
}
Expand All @@ -68,6 +69,7 @@ func (r *Root) RunDNS(cmd *cobra.Command, args []string) error {
return err
}

defer r.UpdateHistory()
r.ctx.RecordToSession = true

opts := &globalping.MeasurementCreate{
Expand Down Expand Up @@ -100,7 +102,12 @@ func (r *Root) RunDNS(cmd *cobra.Command, args []string) error {
}

r.ctx.MeasurementsCreated++

hm := &view.HistoryItem{
Id: res.ID,
Status: globalping.StatusInProgress,
StartedAt: r.time.Now(),
}
r.ctx.History.Push(hm)
if r.ctx.RecordToSession {
r.ctx.RecordToSession = false
err := saveIdToSession(res.ID)
Expand Down
20 changes: 16 additions & 4 deletions cmd/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ func Test_Execute_DNS_Default(t *testing.T) {
viewerMock := mocks.NewMockViewer(ctrl)
viewerMock.EXPECT().Output(measurementID1, expectedOpts).Times(1).Return(nil)

timeMock := mocks.NewMockTime(ctrl)
timeMock.EXPECT().Now().Return(defaultCurrentTime).AnyTimes()

w := new(bytes.Buffer)
printer := view.NewPrinter(nil, w, w)
ctx := createDefaultContext()
root := NewRoot(printer, ctx, viewerMock, nil, gbMock, nil)
ctx := createDefaultContext("dns")
root := NewRoot(printer, ctx, viewerMock, timeMock, gbMock, nil)

os.Args = []string{"globalping", "dns", "jsdelivr.com",
"from", "Berlin",
Expand All @@ -67,6 +70,15 @@ func Test_Execute_DNS_Default(t *testing.T) {

b, err := os.ReadFile(getMeasurementsPath())
assert.NoError(t, err)
expectedHistory := []byte(measurementID1 + "\n")
assert.Equal(t, expectedHistory, b)
expectedHistory := measurementID1 + "\n"
assert.Equal(t, expectedHistory, string(b))

b, err = os.ReadFile(getHistoryPath())
assert.NoError(t, err)
expectedHistory = createDefaultExpectedHistoryLogItem(
"1",
measurementID1,
"dns jsdelivr.com from Berlin --limit 2 --type MX --resolver 1.1.1.1 --port 99 --protocol tcp --trace",
)
assert.Equal(t, expectedHistory, string(b))
}
Loading