Skip to content
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
2 changes: 1 addition & 1 deletion cmd/state-remote-installer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func execute(out output.Outputer, prompt prompt.Prompter, cfg *config.Instance,
version = fmt.Sprintf("%s (%s)", version, channel)
}

update := updater.NewUpdateInstaller(an, availableUpdate)
update := updater.NewUpdateInstaller(cfg, an, availableUpdate)
out.Fprint(os.Stdout, locale.Tl("remote_install_downloading", "• Downloading State Tool version [NOTICE]{{.V0}}[/RESET]... ", version))
tmpDir, err := update.DownloadAndUnpack()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion cmd/state/autoupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func autoUpdate(svc *model.SvcModel, args []string, childCmd *captain.Command, c
}

avUpdate := updater.NewAvailableUpdate(upd.Channel, upd.Version, upd.Platform, upd.Path, upd.Sha256, "")
up := updater.NewUpdateInstaller(an, avUpdate)
up := updater.NewUpdateInstaller(cfg, an, avUpdate)
if !up.ShouldInstall() {
logging.Debug("Update is not needed")
return false, nil
Expand Down
9 changes: 9 additions & 0 deletions internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@ const OverwriteDefaultSystemPathEnvVarName = "ACTIVESTATE_TEST_SYSTEM_PATH"
// TestAutoUpdateEnvVarName is used to test auto updates, when set to true will always attempt to auto update
const TestAutoUpdateEnvVarName = "ACTIVESTATE_TEST_AUTO_UPDATE"

// TestUpdateInfoURLEnvVarName is used to test update info urls, when set to a url will override the default update info url
const TestUpdateInfoURLEnvVarName = "ACTIVESTATE_TEST_UPDATE_INFO_URL"

// TestUpdateURLEnvVarName is used to test update urls, when set to a url will override the default update url
const TestUpdateURLEnvVarName = "ACTIVESTATE_TEST_UPDATE_URL"

// ForceUpdateEnvVarName is used to force state tool to update, regardless of whether the update is equal to the current version
const ForceUpdateEnvVarName = "ACTIVESTATE_FORCE_UPDATE"

Expand Down Expand Up @@ -418,6 +424,9 @@ const AnalyticsPixelOverrideConfig = "report.analytics.endpoint"
// UpdateEndpointConfig is the config key used to determine the update endpoint to use
const UpdateEndpointConfig = "update.endpoint"

// UpdateInfoEndpointConfig is the config key used to determine the update info endpoint to use
const UpdateInfoEndpointConfig = "update.info.endpoint"

// NotificationsURLConfig is the config key used to determine the notifications url to use
const NotificationsURLConfig = "notifications.endpoint"

Expand Down
2 changes: 1 addition & 1 deletion internal/runners/update/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (u *Update) Run(params *Params) error {
))
}

update := updater.NewUpdateInstaller(u.an, upd)
update := updater.NewUpdateInstaller(u.cfg, u.an, upd)
if !update.ShouldInstall() {
logging.Debug("No update found")
u.out.Print(output.Prepare(
Expand Down
6 changes: 3 additions & 3 deletions internal/updater/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var (
)

func init() {
configMediator.RegisterOption(constants.UpdateEndpointConfig, configMediator.String, "")
configMediator.RegisterOption(constants.UpdateInfoEndpointConfig, configMediator.String, "")
}

type Checker struct {
Expand Down Expand Up @@ -86,8 +86,8 @@ func (u *Checker) infoURL(tag, desiredVersion, branchName, platform, arch string
var (
infoURL string

envUrl = os.Getenv("_TEST_UPDATE_INFO_URL")
cfgUrl = u.cfg.GetString(constants.UpdateEndpointConfig)
envUrl = os.Getenv(constants.TestUpdateInfoURLEnvVarName)
cfgUrl = u.cfg.GetString(constants.UpdateInfoEndpointConfig)
)
switch {
case envUrl != "":
Expand Down
43 changes: 33 additions & 10 deletions internal/updater/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/ActiveState/cli/internal/installation/storage"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/logging"
configMediator "github.com/ActiveState/cli/internal/mediators/config"
"github.com/ActiveState/cli/internal/multilog"
"github.com/ActiveState/cli/internal/osutils"
"github.com/ActiveState/cli/internal/rtutils"
Expand All @@ -34,6 +35,10 @@ const (
InstallerName = "state-installer" + osutils.ExeExtension
)

func init() {
configMediator.RegisterOption(constants.UpdateEndpointConfig, configMediator.String, "")
}

type ErrorInProgress struct{ *locale.LocalizedError }

var errPrivilegeMistmatch = errs.New("Privilege mismatch")
Expand Down Expand Up @@ -101,22 +106,40 @@ type UpdateInstaller struct {

// NewUpdateInstallerByOrigin returns an instance of Update. Allowing origin to
// be set is useful for testing.
func NewUpdateInstallerByOrigin(an analytics.Dispatcher, origin *Origin, avUpdate *AvailableUpdate) *UpdateInstaller {
apiUpdateURL := constants.APIUpdateURL
if url, ok := os.LookupEnv("_TEST_UPDATE_URL"); ok {
apiUpdateURL = url
}

return &UpdateInstaller{
func NewUpdateInstallerByOrigin(cfg Configurable, an analytics.Dispatcher, origin *Origin, avUpdate *AvailableUpdate) *UpdateInstaller {
updater := &UpdateInstaller{
AvailableUpdate: avUpdate,
Origin: origin,
url: apiUpdateURL + "/" + avUpdate.Path,
url: getAPIUpdateURL(cfg, avUpdate.Path),
an: an,
}

configMediator.AddListener(constants.UpdateEndpointConfig, func() {
updater.url = getAPIUpdateURL(cfg, avUpdate.Path)
})

return updater
}

func NewUpdateInstaller(cfg Configurable, an analytics.Dispatcher, avUpdate *AvailableUpdate) *UpdateInstaller {
return NewUpdateInstallerByOrigin(cfg, an, NewOriginDefault(), avUpdate)
}

func NewUpdateInstaller(an analytics.Dispatcher, avUpdate *AvailableUpdate) *UpdateInstaller {
return NewUpdateInstallerByOrigin(an, NewOriginDefault(), avUpdate)
func getAPIUpdateURL(cfg Configurable, path string) string {
var apiUpdateURL string

envUrl := os.Getenv(constants.TestUpdateURLEnvVarName)
cfgUrl := cfg.GetString(constants.UpdateEndpointConfig)
switch {
case envUrl != "":
apiUpdateURL = envUrl
case cfgUrl != "":
apiUpdateURL = cfgUrl
default:
apiUpdateURL = constants.APIUpdateURL
}

return apiUpdateURL + "/" + path
}

func (u *UpdateInstaller) ShouldInstall() bool {
Expand Down
12 changes: 11 additions & 1 deletion internal/updater/updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import (
"github.com/stretchr/testify/assert"
)

type mockConfig struct{}

func (m *mockConfig) GetString(key string) string {
return ""
}

func (m *mockConfig) Set(key string, value interface{}) error {
return nil
}

func newAvailableUpdate(channel, version string) *AvailableUpdate {
return NewAvailableUpdate(channel, version, "platform", "path/to/zipfile.zip", "123456", "")
}
Expand Down Expand Up @@ -45,7 +55,7 @@ func TestUpdateNotNeeded(t *testing.T) {

for _, tt := range tests {
t.Run(tt.Name, func(t *testing.T) {
upd := NewUpdateInstallerByOrigin(nil, tt.Origin, tt.AvailableUpdate)
upd := NewUpdateInstallerByOrigin(&mockConfig{}, nil, tt.Origin, tt.AvailableUpdate)
assert.Equal(t, tt.IsUseful, upd.ShouldInstall())
})
}
Expand Down
82 changes: 74 additions & 8 deletions test/integration/update_int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,14 +275,14 @@ func (suite *UpdateIntegrationTestSuite) TestUpdateTags() {
}
}

func (suite *UpdateIntegrationTestSuite) TestUpdateHost_SetBeforeInvocation() {
func (suite *UpdateIntegrationTestSuite) TestUpdateInfoHost_SetBeforeInvocation() {
suite.OnlyRunForTags(tagsuite.Update)

ts := e2e.New(suite.T(), false)
defer ts.Close()

ts.SetConfig(constants.UpdateEndpointConfig, "https://test.example.com/update")
suite.Assert().Equal(ts.GetConfig(constants.UpdateEndpointConfig), "https://test.example.com/update")
ts.SetConfig(constants.UpdateInfoEndpointConfig, "https://test.example.com/update")
suite.Assert().Equal(ts.GetConfig(constants.UpdateInfoEndpointConfig), "https://test.example.com/update")

cp := ts.SpawnWithOpts(
e2e.OptArgs("--version"),
Expand All @@ -303,6 +303,62 @@ func (suite *UpdateIntegrationTestSuite) TestUpdateHost_SetBeforeInvocation() {
suite.Assert().Greater(correctHostCount, 0, "Log file should contain the configured API host 'test.example.com'")
suite.Assert().Equal(incorrectHostCount, 0, "Log file should not contain the default API host 'platform.activestate.com'")

// Clean up - remove the config setting
cp = ts.Spawn("config", "set", constants.UpdateInfoEndpointConfig, "")
cp.Expect("Successfully")
cp.ExpectExitCode(0)
}

func (suite *UpdateIntegrationTestSuite) TestUpdateInfoHost() {
suite.OnlyRunForTags(tagsuite.Update)

ts := e2e.New(suite.T(), false)
defer ts.Close()

cp := ts.Spawn("config", "set", constants.UpdateInfoEndpointConfig, "https://example.com/update-info")
cp.Expect("Successfully set config key")
cp.ExpectExitCode(0)

cp = ts.SpawnWithOpts(
e2e.OptArgs("update", "-v"),
e2e.OptAppendEnv(suite.env(false, false)...),
)
cp.ExpectExitCode(0)

output := cp.Snapshot()
suite.Assert().Contains(output, "Getting update info: https://example.com/update-info/")
}

func (suite *UpdateIntegrationTestSuite) TestUpdateHost_SetBeforeInvocation() {
suite.OnlyRunForTags(tagsuite.Update)

ts := e2e.New(suite.T(), false)
defer ts.Close()

ts.SetConfig(constants.UpdateInfoEndpointConfig, "https://test.example.com/update")
suite.Assert().Equal(ts.GetConfig(constants.UpdateInfoEndpointConfig), "https://test.example.com/update")

cp := ts.SpawnWithOpts(
e2e.OptArgs("update", "-v"),
e2e.OptAppendEnv(suite.env(false, false)...),
)
cp.ExpectExitCode(11) // Expect failure due to DNS resolution of fake host
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If an error will be logged, then we also need to call ts.IgnoreLogErrors().

The nightly integration tests scan the logs for errors and fail tests if errors are found unless we expect to have them.

ts.IgnoreLogErrors()

correctHostCount := 0
incorrectHostCount := 0
for _, path := range ts.LogFiles() {
contents := string(fileutils.ReadFileUnsafe(path))
if strings.Contains(contents, "https://test.example.com/update") {
correctHostCount++
}
if strings.Contains(contents, "https://state-tool.activestate.com/update") {
incorrectHostCount++
}
}
suite.Assert().Greater(correctHostCount, 0, "Log file should contain the configured update endpoint 'test.example.com'")
suite.Assert().Equal(incorrectHostCount, 0, "Log file should not contain the default update endpoint 'state-tool.activestate.com'")

// Clean up - remove the config setting
cp = ts.Spawn("config", "set", constants.UpdateEndpointConfig, "")
cp.Expect("Successfully")
Expand All @@ -315,19 +371,29 @@ func (suite *UpdateIntegrationTestSuite) TestUpdateHost() {
ts := e2e.New(suite.T(), false)
defer ts.Close()

cp := ts.Spawn("config", "set", constants.UpdateEndpointConfig, "https://example.com/update")
cp := ts.Spawn("config", "set", constants.UpdateEndpointConfig, "https://test.example.com/update")
cp.Expect("Successfully set config key")
cp.ExpectExitCode(0)

cp = ts.SpawnWithOpts(
e2e.OptArgs("update"),
e2e.OptArgs("update", "-v"),
e2e.OptAppendEnv(suite.env(false, false)...),
e2e.OptAppendEnv("VERBOSE=true"),
)
cp.ExpectExitCode(0)

output := cp.Snapshot()
suite.Assert().Contains(output, "Getting update info: https://example.com/update/")
correctHostCount := 0
incorrectHostCount := 0
for _, path := range ts.LogFiles() {
contents := string(fileutils.ReadFileUnsafe(path))
if strings.Contains(contents, "https://test.example.com/update") {
correctHostCount++
}
if strings.Contains(contents, "https://state-tool.activestate.com/update") {
incorrectHostCount++
}
}
suite.Assert().Greater(correctHostCount, 0, "Log file should contain the configured update endpoint 'example.com'")
suite.Assert().Equal(incorrectHostCount, 0, "Log file should not contain the default update endpoint 'state-tool.activestate.com'")
}

func TestUpdateIntegrationTestSuite(t *testing.T) {
Expand Down
Loading