Initial extension update check testing
First pass at implementing basic test around extension state checking behavior, wanting to discus with team about level of testing to perform and whether this is really the right place.
This commit is contained in:
parent
7b91b17395
commit
6bd01d52dd
4 changed files with 150 additions and 4 deletions
|
|
@ -43,9 +43,13 @@ func ShouldCheckForExtensionUpdate() bool {
|
|||
return !IsCI() && IsTerminal(os.Stdout) && IsTerminal(os.Stderr)
|
||||
}
|
||||
|
||||
func CheckForExtensionUpdate(em extensions.ExtensionManager, ext extensions.Extension, stateFilePath string) (*ReleaseInfo, error) {
|
||||
func CheckForExtensionUpdate(em extensions.ExtensionManager, ext extensions.Extension, stateFilePath string, now time.Time) (*ReleaseInfo, error) {
|
||||
if ext.IsLocal() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
stateEntry, _ := getStateEntry(stateFilePath)
|
||||
if stateEntry != nil && time.Since(stateEntry.CheckedForUpdateAt).Hours() < 24 {
|
||||
if stateEntry != nil && now.Sub(stateEntry.CheckedForUpdateAt).Hours() < 24 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,7 @@ func CheckForExtensionUpdate(em extensions.ExtensionManager, ext extensions.Exte
|
|||
URL: ext.URL(),
|
||||
}
|
||||
|
||||
err := setStateEntry(stateFilePath, time.Now(), *releaseInfo)
|
||||
err := setStateEntry(stateFilePath, now, *releaseInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,15 @@ import (
|
|||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/cmd/extension"
|
||||
"github.com/cli/cli/v2/pkg/extensions"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestCheckForUpdate(t *testing.T) {
|
||||
|
|
@ -117,6 +123,136 @@ func TestCheckForUpdate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCheckForExtensionUpdate(t *testing.T) {
|
||||
now := time.Date(2024, 12, 17, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
extCurrentVersion string
|
||||
extLatestVersion string
|
||||
extIsLocal bool
|
||||
extURL string
|
||||
stateEntry *StateEntry
|
||||
ri ReleaseInfo
|
||||
wantErr bool
|
||||
expectedReleaseInfo *ReleaseInfo
|
||||
expectedStateEntry *StateEntry
|
||||
}{
|
||||
{
|
||||
name: "return latest release given extension is out of date and no state entry",
|
||||
extCurrentVersion: "v0.1.0",
|
||||
extLatestVersion: "v1.0.0",
|
||||
extIsLocal: false,
|
||||
extURL: "http://example.com",
|
||||
stateEntry: nil,
|
||||
expectedReleaseInfo: &ReleaseInfo{
|
||||
Version: "v1.0.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
expectedStateEntry: &StateEntry{
|
||||
CheckedForUpdateAt: now,
|
||||
LatestRelease: ReleaseInfo{
|
||||
Version: "v1.0.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "return latest release given extension is out of date and state entry is old enough",
|
||||
extCurrentVersion: "v0.1.0",
|
||||
extLatestVersion: "v1.0.0",
|
||||
extIsLocal: false,
|
||||
extURL: "http://example.com",
|
||||
stateEntry: &StateEntry{
|
||||
CheckedForUpdateAt: now.Add(-24 * time.Hour),
|
||||
LatestRelease: ReleaseInfo{
|
||||
Version: "v0.1.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
},
|
||||
expectedReleaseInfo: &ReleaseInfo{
|
||||
Version: "v1.0.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
expectedStateEntry: &StateEntry{
|
||||
CheckedForUpdateAt: now,
|
||||
LatestRelease: ReleaseInfo{
|
||||
Version: "v1.0.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "return nothing given extension is out of date but state entry is too recent",
|
||||
extCurrentVersion: "v0.1.0",
|
||||
extLatestVersion: "v1.0.0",
|
||||
extIsLocal: false,
|
||||
extURL: "http://example.com",
|
||||
stateEntry: &StateEntry{
|
||||
CheckedForUpdateAt: now.Add(-23 * time.Hour),
|
||||
LatestRelease: ReleaseInfo{
|
||||
Version: "v0.1.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
},
|
||||
expectedReleaseInfo: nil,
|
||||
expectedStateEntry: &StateEntry{
|
||||
CheckedForUpdateAt: now.Add(-23 * time.Hour),
|
||||
LatestRelease: ReleaseInfo{
|
||||
Version: "v0.1.0",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
em := &extensions.ExtensionManagerMock{}
|
||||
|
||||
ext := &extensions.ExtensionMock{
|
||||
CurrentVersionFunc: func() string {
|
||||
return tt.extCurrentVersion
|
||||
},
|
||||
LatestVersionFunc: func() string {
|
||||
return tt.extLatestVersion
|
||||
},
|
||||
IsLocalFunc: func() bool {
|
||||
return tt.extIsLocal
|
||||
},
|
||||
URLFunc: func() string {
|
||||
return tt.extURL
|
||||
},
|
||||
}
|
||||
|
||||
// Ensure test is testing actual update available logic
|
||||
ext.UpdateAvailableFunc = func() bool {
|
||||
// Should this function be removed from the extension interface?
|
||||
return extension.UpdateAvailable(ext)
|
||||
}
|
||||
|
||||
// Create state file for test as necessary
|
||||
stateFilePath := filepath.Join(t.TempDir(), "state.yml")
|
||||
if tt.stateEntry != nil {
|
||||
stateEntryYaml, err := yaml.Marshal(tt.stateEntry)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, os.WriteFile(stateFilePath, stateEntryYaml, 0644))
|
||||
}
|
||||
|
||||
actual, err := CheckForExtensionUpdate(em, ext, stateFilePath, now)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.Equal(t, tt.expectedReleaseInfo, actual)
|
||||
|
||||
stateEntry, err := getStateEntry(stateFilePath)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expectedStateEntry, stateEntry)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func tempFilePath() string {
|
||||
file, err := os.CreateTemp("", "")
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/extensions"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
|
|
@ -215,6 +216,10 @@ func (e *Extension) Owner() string {
|
|||
}
|
||||
|
||||
func (e *Extension) UpdateAvailable() bool {
|
||||
return UpdateAvailable(e)
|
||||
}
|
||||
|
||||
func UpdateAvailable(e extensions.Extension) bool {
|
||||
if e.IsLocal() ||
|
||||
e.CurrentVersion() == "" ||
|
||||
e.LatestVersion() == "" ||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/update"
|
||||
|
|
@ -83,5 +84,5 @@ func checkForExtensionUpdate(em extensions.ExtensionManager, ext extensions.Exte
|
|||
}
|
||||
|
||||
stateFilePath := filepath.Join(config.StateDir(), "extensions", ext.FullName(), "state.yml")
|
||||
return update.CheckForExtensionUpdate(em, ext, stateFilePath)
|
||||
return update.CheckForExtensionUpdate(em, ext, stateFilePath, time.Now())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue