Skip to content

Commit fc68763

Browse files
committed
Adds more unit tests
1 parent e771d11 commit fc68763

11 files changed

Lines changed: 1329 additions & 51 deletions

File tree

internal/cleanup/cleanup.go

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@ package cleanup
22

33
import (
44
"fmt"
5-
"os"
65
"path/filepath"
7-
"strconv"
86

9-
"github.com/!azure/azure-extension-platform/pkg/utils"
107
"github.com/Azure/run-command-handler-linux/internal/constants"
118
"github.com/Azure/run-command-handler-linux/internal/types"
129
"github.com/Azure/run-command-handler-linux/pkg/linuxutils"
@@ -41,28 +38,28 @@ func deleteAllScriptsAndSettings(ctx *log.Context, metadata types.RCMetadata, h
4138
}
4239

4340
func deleteScriptsAndSettingsExceptMostRecent(ctx *log.Context, metadata types.RCMetadata, h types.HandlerEnvironment, runAsUser string) {
44-
runtimeSettingsRegexFormat := metadata.ExtName + ".\\d+.settings"
45-
runtimeSettingsLastSeqNumFormat := metadata.ExtName + ".%d.settings"
41+
/* runtimeSettingsRegexFormat := metadata.ExtName + ".\\d+.settings"
42+
runtimeSettingsLastSeqNumFormat := metadata.ExtName + ".%d.settings"
4643
47-
// check if directory exists
48-
_, err := os.Open(metadata.DownloadPath)
49-
if err == nil {
50-
err := utils.TryClearExtensionScriptsDirectoriesAndSettingsFilesExceptMostRecent(metadata.DownloadPath, h.HandlerEnvironment.ConfigFolder, "",
51-
uint64(metadata.SeqNum), runtimeSettingsRegexFormat, runtimeSettingsLastSeqNumFormat)
52-
if err != nil {
53-
ctx.Log("event", "could not clear settings and script files", "error", err)
54-
}
55-
} else {
56-
ctx.Log("message", "directory does not exist. Skipping cleanup")
57-
}
44+
// check if directory exists
45+
_, err := os.Open(metadata.DownloadPath)
46+
if err == nil {
47+
err := utils.TryClearExtensionScriptsDirectoriesAndSettingsFilesExceptMostRecent(metadata.DownloadPath, h.HandlerEnvironment.ConfigFolder, "",
48+
uint64(metadata.SeqNum), runtimeSettingsRegexFormat, runtimeSettingsLastSeqNumFormat)
49+
if err != nil {
50+
ctx.Log("event", "could not clear settings and script files", "error", err)
51+
}
52+
} else {
53+
ctx.Log("message", "directory does not exist. Skipping cleanup")
54+
}
5855
59-
if runAsUser != "" {
60-
runAsDownloadParent := filepath.Join(fmt.Sprintf(constants.RunAsDir, runAsUser), metadata.DownloadDir)
61-
seqNumString := strconv.Itoa(metadata.SeqNum)
62-
ctx.Log("message", "removing all files from the download 'runas' directory "+runAsDownloadParent)
63-
err = utils.TryDeleteDirectoriesExcept(runAsDownloadParent, seqNumString)
64-
if err != nil {
65-
ctx.Log("event", "could not clear runas script")
66-
}
67-
}
56+
if runAsUser != "" {
57+
runAsDownloadParent := filepath.Join(fmt.Sprintf(constants.RunAsDir, runAsUser), metadata.DownloadDir)
58+
seqNumString := strconv.Itoa(metadata.SeqNum)
59+
ctx.Log("message", "removing all files from the download 'runas' directory "+runAsDownloadParent)
60+
err = utils.TryDeleteDirectoriesExcept(runAsDownloadParent, seqNumString)
61+
if err != nil {
62+
ctx.Log("event", "could not clear runas script")
63+
}
64+
} */
6865
}

internal/commandProcessor/commandProcessor.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
"github.com/Azure/azure-extension-platform/pkg/handlerenv"
1212
"github.com/Azure/azure-extension-platform/pkg/logging"
13+
"github.com/Azure/azure-extension-platform/vmextension"
1314
"github.com/Azure/run-command-handler-linux/internal/constants"
1415
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
1516
"github.com/Azure/run-command-handler-linux/internal/instanceview"
@@ -22,6 +23,8 @@ import (
2223

2324
var (
2425
handlerEnvironmentGetter func(name, version string) (he *handlerenv.HandlerEnvironment, _ error) = handlerenv.GetHandlerEnvironment
26+
fnGetHandlerSettings = handlersettings.GetHandlerSettings
27+
fnReportInstanceView = instanceview.ReportInstanceView
2528
)
2629

2730
func ProcessImmediateHandlerCommand(cmd types.Cmd, hs handlersettings.HandlerSettingsFile, extensionName string, seqNum int) error {
@@ -82,7 +85,7 @@ func ProcessHandlerCommandWithDetails(ctx *log.Context, cmd types.Cmd, hEnv type
8285
}
8386

8487
metadata := types.NewRCMetadata(extensionName, seqNum, downloadFolder, constants.DataDir)
85-
instanceview.ReportInstanceView(ctx, hEnv, metadata, types.StatusTransitioning, cmd, &instView)
88+
fnReportInstanceView(ctx, hEnv, metadata, types.StatusTransitioning, cmd, &instView)
8689

8790
// execute the subcommand
8891
stdout, stderr, cmdInvokeError, exitCode := cmd.Functions.Invoke(ctx, hEnv, &instView, metadata, cmd)
@@ -97,13 +100,19 @@ func ProcessHandlerCommandWithDetails(ctx *log.Context, cmd types.Cmd, hEnv type
97100
instView.ExitCode = exitCode
98101
statusToReport := types.StatusSuccess
99102

103+
// Add an error clarification if we have one
104+
var ewc vmextension.ErrorWithClarification
105+
if errors.As(cmdInvokeError, &ewc) {
106+
instView.ErrorClarificationValue = ewc.ErrorCode
107+
}
108+
100109
// If TreatFailureAsDeploymentFailure is set to true and the exit code is non-zero, set extension status to error
101-
cfg, err := handlersettings.GetHandlerSettings(hEnv.HandlerEnvironment.ConfigFolder, extensionName, seqNum, ctx)
110+
cfg, err := fnGetHandlerSettings(hEnv.HandlerEnvironment.ConfigFolder, extensionName, seqNum, ctx)
102111
if err == nil && cfg.PublicSettings.TreatFailureAsDeploymentFailure && cmd.FailExitCode != 0 {
103112
statusToReport = types.StatusError
104113
}
105114

106-
instanceview.ReportInstanceView(ctx, hEnv, metadata, statusToReport, cmd, &instView)
115+
fnReportInstanceView(ctx, hEnv, metadata, statusToReport, cmd, &instView)
107116
return errors.Wrapf(err, "command execution failed")
108117
} else { // No error. Succeeded
109118
instView.ExecutionMessage = "Execution completed"
@@ -112,7 +121,7 @@ func ProcessHandlerCommandWithDetails(ctx *log.Context, cmd types.Cmd, hEnv type
112121
instView.ExitCode = constants.ExitCode_Okay
113122
}
114123

115-
instanceview.ReportInstanceView(ctx, hEnv, metadata, types.StatusSuccess, cmd, &instView)
124+
fnReportInstanceView(ctx, hEnv, metadata, types.StatusSuccess, cmd, &instView)
116125
ctx.Log("event", "end")
117126

118127
return nil

internal/commandProcessor/commandProcessor_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"testing"
1313
"time"
1414

15+
"github.com/Azure/azure-extension-platform/vmextension"
1516
"github.com/Azure/run-command-handler-linux/internal/cleanup"
1617
"github.com/Azure/run-command-handler-linux/internal/constants"
1718
"github.com/Azure/run-command-handler-linux/internal/handlersettings"
@@ -190,3 +191,43 @@ func Test_GetSeqNumFromFailedToFind(t *testing.T) {
190191
require.Nil(t, err)
191192
require.Equal(t, 0, actualSeqNum)
192193
}
194+
195+
func Test_ProcessHandlerCommandWithDetails_Failure_WithClarification(t *testing.T) {
196+
var last types.RunCommandInstanceView
197+
198+
origReportInstanceView := fnReportInstanceView
199+
defer func() { fnReportInstanceView = origReportInstanceView }()
200+
fnReportInstanceView = func(ctx *log.Context, hEnv types.HandlerEnvironment, metadata types.RCMetadata, t types.StatusType, c types.Cmd, instanceview *types.RunCommandInstanceView) error {
201+
last = *instanceview
202+
return nil
203+
}
204+
205+
ewc := vmextension.ErrorWithClarification{
206+
ErrorCode: 1234,
207+
Err: errors.New("the chipmunks are upset"),
208+
}
209+
210+
mockFunc := types.CmdFunctions{
211+
Invoke: func(_ *log.Context, _ types.HandlerEnvironment, iv *types.RunCommandInstanceView, _ types.RCMetadata, _ types.Cmd) (string, string, error, int) {
212+
return "x", "y", ewc, 3
213+
},
214+
}
215+
216+
orig := fnGetHandlerSettings
217+
defer func() { fnGetHandlerSettings = orig }()
218+
fnGetHandlerSettings = func(string, string, int, *log.Context) (handlersettings.HandlerSettings, error) {
219+
return handlersettings.HandlerSettings{
220+
PublicSettings: handlersettings.PublicSettings{
221+
TreatFailureAsDeploymentFailure: false,
222+
},
223+
}, nil
224+
}
225+
226+
cmd := types.Cmd{Name: "run", FailExitCode: 3, Functions: mockFunc}
227+
hEnv := types.HandlerEnvironment{}
228+
ctx := log.NewContext(log.NewNopLogger())
229+
230+
err := ProcessHandlerCommandWithDetails(ctx, cmd, hEnv, "x", 1, "/tmp")
231+
require.Nil(t, err, "expected no error because TreatFailureAsDeploymentFailure is false")
232+
require.Equal(t, 1234, last.ErrorClarificationValue, "expected clarification 1234 but got %d", last.ErrorClarificationValue)
233+
}

internal/immediatecmds/immediatecmds.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,29 @@ import (
1313
"github.com/pkg/errors"
1414
)
1515

16+
var (
17+
fnServiceDisable = service.Disable
18+
fnServiceDeRegister = service.DeRegister
19+
fnServiceEnable = service.Enable
20+
fnServiceIsEnabled = service.IsEnabled
21+
fnServiceIsInstalled = service.IsInstalled
22+
fnServiceRegister = service.Register
23+
fnServiceStart = service.Start
24+
)
25+
1626
// Updates the service definition if any immediate run command service exists.
1727
// The action is skipped if the service has already been upgraded.
1828
func Update(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
1929
ctx.Log("message", "updating immediate run command")
20-
isInstalled, err := service.IsInstalled(ctx)
30+
isInstalled, err := fnServiceIsInstalled(ctx)
2131
if err != nil {
2232
errMessage := fmt.Sprintf("Failed to check if any runcommand service is installed: %v", err)
2333
extensionEvents.LogErrorEvent("immediateupdate", errMessage)
2434
return constants.FileSystem_CreateDataDirectoryFailed, errors.Wrap(err, "failed to check if any runcommand service is installed")
2535
}
2636

2737
if isInstalled {
28-
err = service.Register(ctx, extensionEvents)
38+
err = fnServiceRegister(ctx, extensionEvents)
2939
if err != nil {
3040
errMessage := fmt.Sprintf("Failed to upgrade run command service: %v", err)
3141
extensionEvents.LogErrorEvent("immediateupdate", errMessage)
@@ -37,23 +47,23 @@ func Update(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum
3747
}
3848

3949
func Disable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
40-
isInstalled, err := service.IsInstalled(ctx)
50+
isInstalled, err := fnServiceIsInstalled(ctx)
4151
if err != nil {
4252
errMessage := fmt.Sprintf("Failed to check if runcommand service is installed: %v", err)
4353
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
4454
return constants.ExitCode_DisableInstalledServiceFailed, errors.Wrap(err, "failed to check if runcommand service is installed")
4555
}
4656

4757
if isInstalled {
48-
isEnabled, err := service.IsEnabled(ctx)
58+
isEnabled, err := fnServiceIsEnabled(ctx)
4959
if err != nil {
5060
errMessage := fmt.Sprintf("Failed to check if service is enabled: %v", err)
5161
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
5262
return constants.ExitCode_InstallServiceFailed, errors.Wrap(err, "failed to check if service is enabled")
5363
}
5464

5565
if isEnabled {
56-
err := service.Disable(ctx, extensionEvents)
66+
err := fnServiceDisable(ctx, extensionEvents)
5767
if err != nil {
5868
errMessage := fmt.Sprintf("Failed to disable run command service: %v", err)
5969
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
@@ -75,19 +85,19 @@ func Install() (int, error) {
7585

7686
func Uninstall(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
7787
ctx.Log("message", "proceeding to uninstall immediate run command")
78-
isInstalled, err := service.IsInstalled(ctx)
88+
isInstalled, err := fnServiceIsInstalled(ctx)
7989
if err != nil {
8090
errMessage := fmt.Sprintf("Failed to check if runcommand service is installed: %v", err)
8191
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
8292
return constants.FileSystem_RemoveDataDirectoryFailed, errors.Wrap(err, "failed to check if runcommand service is installed")
8393
}
8494

8595
if isInstalled {
86-
error := service.DeRegister(ctx, extensionEvents)
87-
if error != nil {
88-
errMessage := fmt.Sprintf("Failed to uninstall run command service: %v", error)
96+
err2 := fnServiceDeRegister(ctx, extensionEvents)
97+
if err2 != nil {
98+
errMessage := fmt.Sprintf("Failed to uninstall run command service: %v", err2)
8999
extensionEvents.LogErrorEvent("immediatedisable", errMessage)
90-
return constants.ExitCode_UninstallInstalledServiceFailed, errors.Wrap(err, "failed to uninstall run command service")
100+
return constants.ExitCode_UninstallInstalledServiceFailed, errors.Wrap(err2, "failed to uninstall run command service")
91101
}
92102
}
93103
return constants.ExitCode_Okay, nil
@@ -96,37 +106,37 @@ func Uninstall(ctx *log.Context, h types.HandlerEnvironment, extName string, seq
96106
func Enable(ctx *log.Context, h types.HandlerEnvironment, extName string, seqNum int, cfg handlersettings.HandlerSettings, extensionEvents *extensionevents.ExtensionEventManager) (int, error) {
97107
// If installService == true, then install RunCommand as a service
98108
if cfg.InstallAsService() {
99-
isInstalled, err2 := service.IsInstalled(ctx)
109+
isInstalled, err2 := fnServiceIsInstalled(ctx)
100110
if err2 != nil {
101111
ctx.Log("message", "could not check if service is already installed. Proceeding to overwrite configuration file to make sure it gets installed.")
102112
extensionEvents.LogErrorEvent("immediateenable", "could not check if service is already installed. Proceeding to overwrite configuration file to make sure it gets installed.")
103113
}
104114

105115
if !isInstalled {
106-
err3 := service.Register(ctx, extensionEvents)
116+
err3 := fnServiceRegister(ctx, extensionEvents)
107117
if err3 != nil {
108118
errMessage := fmt.Sprintf("Failed to install RunCommand as a service: %v", err3)
109119
extensionEvents.LogErrorEvent("immediateenable", errMessage)
110120
return constants.Immediate_CouldNotStartService, err3
111121
}
112122
} else {
113-
isEnabled, err3 := service.IsEnabled(ctx)
123+
isEnabled, err3 := fnServiceIsEnabled(ctx)
114124
if err3 != nil {
115125
errMessage := fmt.Sprintf("Failed to check if service is already enabled: %v", err3)
116126
extensionEvents.LogErrorEvent("immediateenable", errMessage)
117127
return constants.Immediate_CouldNotCheckServiceAlreadyEnabled, vmextension.NewErrorWithClarification(constants.Immediate_CouldNotCheckServiceAlreadyEnabled, errors.Wrap(err3, errMessage))
118128
}
119129

120130
if !isEnabled {
121-
err4 := service.Enable(ctx, extensionEvents)
131+
err4 := fnServiceEnable(ctx, extensionEvents)
122132

123133
if err4 != nil {
124134
errMessage := fmt.Sprintf("Failed to enable service: %v", err4)
125135
extensionEvents.LogErrorEvent("immediateenable", errMessage)
126136
return constants.Immediate_EnableServiceFailed, vmextension.NewErrorWithClarification(constants.Immediate_EnableServiceFailed, errors.Wrap(err4, errMessage))
127137
}
128138

129-
err5 := service.Start(ctx, extensionEvents)
139+
err5 := fnServiceStart(ctx, extensionEvents)
130140

131141
if err5 != nil {
132142
errMessage := fmt.Sprintf("Failed to start service: %v", err5)

0 commit comments

Comments
 (0)