Skip to content

Commit

Permalink
New param --offline-only
Browse files Browse the repository at this point in the history
  • Loading branch information
alanhamlett committed Jul 19, 2024
1 parent b8816ca commit df215b4
Show file tree
Hide file tree
Showing 12 changed files with 104 additions and 31 deletions.
2 changes: 2 additions & 0 deletions cmd/heartbeat/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func SendHeartbeats(v *viper.Viper, queueFilepath string) error {
}

handleOpts = append(handleOpts, offline.WithQueue(queueFilepath))
} else if params.Offline.OfflineOnly {
return errors.New("--offline-only can NOT be used with --disable-offline")
}

handleOpts = append(handleOpts, backoff.WithBackoff(backoff.Config{
Expand Down
6 changes: 3 additions & 3 deletions cmd/offline/offline.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import (
"github.com/spf13/viper"
)

// SaveHeartbeats saves heartbeats to the offline db, when we haven't
// tried sending them to the API. If we tried sending to API already,
// to the API. Used when we have heartbeats unsent to API.
// SaveHeartbeats saves heartbeats to the offline db without trying to send to the API.
// Used when we have more heartbeats than `offline.SendLimit`, when --offline-only enabled,
// when we couldn't send heartbeats to the API, or the API returned an auth error.
func SaveHeartbeats(v *viper.Viper, heartbeats []heartbeat.Heartbeat, queueFilepath string) error {
params, err := loadParams(v)
if err != nil {
Expand Down
9 changes: 6 additions & 3 deletions cmd/params/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,10 @@ type (
// Offline contains offline related parameters.
Offline struct {
Disabled bool
OfflineOnly bool
PrintMax int
QueueFile string
QueueFileLegacy string
PrintMax int
SyncMax int
}

Expand Down Expand Up @@ -656,9 +657,10 @@ func LoadOfflineParams(v *viper.Viper) Offline {

return Offline{
Disabled: disabled,
OfflineOnly: v.GetBool("offline-only"),
PrintMax: v.GetInt("print-offline-heartbeats"),
QueueFile: vipertools.GetString(v, "offline-queue-file"),
QueueFileLegacy: vipertools.GetString(v, "offline-queue-file-legacy"),
PrintMax: v.GetInt("print-offline-heartbeats"),
SyncMax: syncMax,
}
}
Expand Down Expand Up @@ -1039,8 +1041,9 @@ func (p Heartbeat) String() string {
// String implements fmt.Stringer interface.
func (p Offline) String() string {
return fmt.Sprintf(
"disabled: %t, print max: %d, queue file: '%s', queue file legacy: '%s', num sync max: %d",
"disabled: %t, offline only: %t, print max: %d, queue file: '%s', queue file legacy: '%s', num sync max: %d",
p.Disabled,
p.OfflineOnly,
p.PrintMax,
p.QueueFile,
p.QueueFileLegacy,
Expand Down
2 changes: 1 addition & 1 deletion cmd/params/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2505,7 +2505,7 @@ func TestOffline_String(t *testing.T) {

assert.Equal(
t,
"disabled: true, print max: 6, queue file: '/path/to/queue.file',"+
"disabled: true, offline only: false, print max: 6, queue file: '/path/to/queue.file',"+
" queue file legacy: '/path/to/legacy.file', num sync max: 12",
offline.String(),
)
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ func setFlags(cmd *cobra.Command, v *viper.Viper) {
" new heartbeats.", offline.SyncMaxDefault),
)
flags.Bool("offline-count", false, "Prints the number of heartbeats in the offline db, then exits.")
flags.Bool("offline-only", false, "Saves the heartbeat(s) to the offline db, then exits.")
flags.Int(
"timeout",
api.DefaultTimeoutSecs,
Expand Down
8 changes: 7 additions & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,13 @@ func Run(cmd *cobra.Command, v *viper.Viper) {
if v.IsSet("entity") {
log.Debugln("command: heartbeat")

RunCmdWithOfflineSync(v, logFileParams.Verbose, logFileParams.SendDiagsOnErrors, cmdheartbeat.Run, shutdown)
if v.GetBool("offline-only") {
saveHeartbeats(v)
shutdown()
os.Exit(exitcode.Success)
} else {

Check warning on line 141 in cmd/run.go

View workflow job for this annotation

GitHub Actions / Unit Tests

superfluous-else: if block ends with call to os.Exit function, so drop this else and outdent its block (revive)

Check warning on line 141 in cmd/run.go

View workflow job for this annotation

GitHub Actions / Unit Tests Windows

superfluous-else: if block ends with call to os.Exit function, so drop this else and outdent its block (revive)

Check warning on line 141 in cmd/run.go

View workflow job for this annotation

GitHub Actions / Unit Tests macOS

superfluous-else: if block ends with call to os.Exit function, so drop this else and outdent its block (revive)
RunCmdWithOfflineSync(v, logFileParams.Verbose, logFileParams.SendDiagsOnErrors, cmdheartbeat.Run, shutdown)
}
}

if v.IsSet("sync-offline-activity") {
Expand Down
56 changes: 56 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,62 @@ func TestSendHeartbeats_ExtraHeartbeats_SyncLegacyOfflineActivity(t *testing.T)
assert.Eventually(t, func() bool { return numCalls == 3 }, time.Second, 50*time.Millisecond)
}

func TestSendHeartbeats_OfflineOnly(t *testing.T) {
apiURL, router, close := setupTestServer()
defer close()

router.HandleFunc("/users/current/heartbeats.bulk", func(w http.ResponseWriter, req *http.Request) {

Check warning on line 465 in main_test.go

View workflow job for this annotation

GitHub Actions / Unit Tests

unused-parameter: parameter 'w' seems to be unused, consider removing or renaming it as _ (revive)

Check warning on line 465 in main_test.go

View workflow job for this annotation

GitHub Actions / Unit Tests Windows

unused-parameter: parameter 'w' seems to be unused, consider removing or renaming it as _ (revive)

Check warning on line 465 in main_test.go

View workflow job for this annotation

GitHub Actions / Unit Tests macOS

unused-parameter: parameter 'w' seems to be unused, consider removing or renaming it as _ (revive)
require.FailNow(t, "Should not make any API request")
})

tmpDir := t.TempDir()

offlineQueueFile, err := os.CreateTemp(tmpDir, "")
require.NoError(t, err)

defer offlineQueueFile.Close()

tmpConfigFile, err := os.CreateTemp(tmpDir, "wakatime.cfg")
require.NoError(t, err)

defer tmpConfigFile.Close()

tmpInternalConfigFile, err := os.CreateTemp(tmpDir, "wakatime-internal.cfg")
require.NoError(t, err)

defer tmpInternalConfigFile.Close()

data, err := os.ReadFile("testdata/extra_heartbeats.json")
require.NoError(t, err)

buffer := bytes.NewBuffer(data)

runWakatimeCli(
t,
buffer,
"--api-url", apiURL,
"--key", "00000000-0000-4000-8000-000000000000",
"--config", tmpConfigFile.Name(),
"--internal-config", tmpInternalConfigFile.Name(),
"--entity", "testdata/main.go",
"--extra-heartbeats", "true",
"--cursorpos", "12",
"--offline-queue-file", offlineQueueFile.Name(),
"--offline-only",
"--lineno", "42",
"--lines-in-file", "100",
"--time", "1585598059",
"--hide-branch-names", ".*",
"--write",
"--verbose",
)

offlineCount, err := offline.CountHeartbeats(offlineQueueFile.Name())
require.NoError(t, err)

assert.Equal(t, 27, offlineCount)
}

func TestSendHeartbeats_Err(t *testing.T) {
apiURL, router, close := setupTestServer()
defer close()
Expand Down
8 changes: 7 additions & 1 deletion pkg/heartbeat/heartbeat.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,14 @@ func (h Heartbeat) ID() string {
isWrite = *h.IsWrite
}

return fmt.Sprintf("%f-%s-%s-%s-%s-%s-%t",
cursorPos := "nil"
if h.CursorPosition != nil {
cursorPos = fmt.Sprint(*h.CursorPosition)
}

return fmt.Sprintf("%f-%s-%s-%s-%s-%s-%s-%t",
h.Time,
cursorPos,
h.EntityType,
h.Category,
project,
Expand Down
4 changes: 2 additions & 2 deletions pkg/heartbeat/heartbeat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestHeartbeat_ID(t *testing.T) {
Project: heartbeat.PointerTo("wakatime"),
Time: 1592868313.541149,
}
assert.Equal(t, "1592868313.541149-file-coding-wakatime-heartbeat-/tmp/main.go-true", h.ID())
assert.Equal(t, "1592868313.541149-nil-file-coding-wakatime-heartbeat-/tmp/main.go-true", h.ID())
}

func TestHeartbeat_ID_NilFields(t *testing.T) {
Expand All @@ -85,7 +85,7 @@ func TestHeartbeat_ID_NilFields(t *testing.T) {
EntityType: heartbeat.FileType,
Time: 1592868313.541149,
}
assert.Equal(t, "1592868313.541149-file-coding-unset-unset-/tmp/main.go-false", h.ID())
assert.Equal(t, "1592868313.541149-nil-file-coding-unset-unset-/tmp/main.go-false", h.ID())
}

func TestHeartbeat_JSON(t *testing.T) {
Expand Down
5 changes: 2 additions & 3 deletions pkg/offline/offline.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,13 @@ func WithQueue(filepath string) heartbeat.HandleOption {

results, err := next(hh)
if err != nil {
log.Debugf("pushing %d heartbeat(s) to queue due to error", len(hh))
log.Debugf("pushing %d heartbeat(s) to queue after error: %s", len(hh), err)

requeueErr := pushHeartbeatsWithRetry(filepath, hh)
if requeueErr != nil {
return nil, fmt.Errorf(
"failed to push heartbeats to queue after api error: %w. error: %w",
"failed to push heartbeats to queue: %s",
requeueErr,
err,
)
}

Expand Down
32 changes: 16 additions & 16 deletions pkg/offline/offline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,10 @@ func TestWithQueue_ApiError(t *testing.T) {

require.Len(t, stored, 2)

assert.Equal(t, "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.Equal(t, "1592868367.219124-12-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.JSONEq(t, string(dataGo), stored[0].Heartbeat)

assert.Equal(t, "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.Equal(t, "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.JSONEq(t, string(dataPy), stored[1].Heartbeat)
}

Expand Down Expand Up @@ -307,10 +307,10 @@ func TestWithQueue_InvalidResults(t *testing.T) {

assert.Len(t, stored, 2)

assert.Equal(t, "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false", stored[0].ID)
assert.Equal(t, "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false", stored[0].ID)
assert.JSONEq(t, string(dataPy), stored[0].Heartbeat)

assert.Equal(t, "1592868394.084354-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[1].ID)
assert.Equal(t, "1592868394.084354-14-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[1].ID)
assert.JSONEq(t, string(dataJs), stored[1].Heartbeat)
}

Expand Down Expand Up @@ -376,10 +376,10 @@ func TestWithQueue_HandleLeftovers(t *testing.T) {

require.Len(t, stored, 2)

assert.Equal(t, "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false", stored[0].ID)
assert.Equal(t, "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false", stored[0].ID)
assert.JSONEq(t, string(dataPy), stored[0].Heartbeat)

assert.Equal(t, "1592868394.084354-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[1].ID)
assert.Equal(t, "1592868394.084354-14-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[1].ID)
assert.JSONEq(t, string(dataJs), stored[1].Heartbeat)
}

Expand All @@ -401,11 +401,11 @@ func TestWithSync(t *testing.T) {

insertHeartbeatRecords(t, db, "heartbeats", []heartbeatRecord{
{
ID: "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
ID: "1592868367.219124-12-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
Heartbeat: string(dataGo),
},
{
ID: "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false",
ID: "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false",
Heartbeat: string(dataPy),
},
})
Expand Down Expand Up @@ -571,11 +571,11 @@ func TestSync_APIError(t *testing.T) {

insertHeartbeatRecords(t, db, "heartbeats", []heartbeatRecord{
{
ID: "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
ID: "1592868367.219124-12-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
Heartbeat: string(dataGo),
},
{
ID: "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false",
ID: "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false",
Heartbeat: string(dataPy),
},
})
Expand Down Expand Up @@ -625,10 +625,10 @@ func TestSync_APIError(t *testing.T) {

require.Len(t, stored, 2)

assert.Equal(t, "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.Equal(t, "1592868367.219124-12-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.JSONEq(t, string(dataGo), stored[0].Heartbeat)

assert.Equal(t, "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.Equal(t, "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.JSONEq(t, string(dataPy), stored[1].Heartbeat)

assert.Eventually(t, func() bool { return numCalls == 1 }, time.Second, 50*time.Millisecond)
Expand Down Expand Up @@ -1189,7 +1189,7 @@ func TestQueue_PushMany(t *testing.T) {
require.NoError(t, err)

insertHeartbeatRecord(t, db, "test_bucket", heartbeatRecord{
ID: "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
ID: "1592868367.219124-1-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true",
Heartbeat: string(dataGo),
})

Expand Down Expand Up @@ -1240,13 +1240,13 @@ func TestQueue_PushMany(t *testing.T) {

assert.Len(t, stored, 3)

assert.Equal(t, "1592868367.219124-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.Equal(t, "1592868367.219124-1-file-coding-wakatime-cli-heartbeat-/tmp/main.go-true", stored[0].ID)
assert.JSONEq(t, string(dataGo), stored[0].Heartbeat)

assert.Equal(t, "1592868386.079084-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.Equal(t, "1592868386.079084-13-file-debugging-wakatime-summary-/tmp/main.py-false", stored[1].ID)
assert.JSONEq(t, string(dataPy), stored[1].Heartbeat)

assert.Equal(t, "1592868394.084354-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[2].ID)
assert.Equal(t, "1592868394.084354-14-file-building-wakatime-todaygoal-/tmp/main.js-false", stored[2].ID)
assert.JSONEq(t, string(dataJs), stored[2].Heartbeat)
}

Expand Down
Loading

0 comments on commit df215b4

Please sign in to comment.