Skip to content

Commit db47e15

Browse files
committed
BIF-1093 Send configuration failure callbacks back to JSM
1 parent a242bee commit db47e15

File tree

4 files changed

+99
-43
lines changed

4 files changed

+99
-43
lines changed

queue/job.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,23 +81,26 @@ func (j *job) Execute() error {
8181
}
8282

8383
result, err := j.messageHandler.Handle(j.message)
84+
85+
if result != nil {
86+
go func() {
87+
start := time.Now()
88+
89+
err = runbook.SendResultToJsmFunc(result, j.apiKey, j.baseUrl)
90+
if err != nil {
91+
logrus.Warnf("Could not send action result[%+v] of message[%s] to Jira Service Management: %s", result, messageId, err)
92+
} else {
93+
took := time.Since(start)
94+
logrus.Debugf("Successfully sent result of message[%s] to Jira Service Management and it took %f seconds.", messageId, took.Seconds())
95+
}
96+
}()
97+
}
98+
8499
if err != nil {
85100
j.state = jobError
86101
return errors.Errorf("Message[%s] could not be processed: %s", messageId, err)
87102
}
88103

89-
go func() {
90-
start := time.Now()
91-
92-
err = runbook.SendResultToJsmFunc(result, j.apiKey, j.baseUrl)
93-
if err != nil {
94-
logrus.Warnf("Could not send action result[%+v] of message[%s] to Jira Service Management: %s", result, messageId, err)
95-
} else {
96-
took := time.Since(start)
97-
logrus.Debugf("Successfully sent result of message[%s] to Jira Service Management and it took %f seconds.", messageId, took.Seconds())
98-
}
99-
}()
100-
101104
j.state = jobFinished
102105
return nil
103106
}

queue/job_test.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import (
1313
"testing"
1414
)
1515

16-
var mockActionResultPayload = &runbook.ActionResultPayload{Action: "MockAction"}
16+
var mockActionResultPayload = &runbook.ActionResultPayload{
17+
Action: "MockAction",
18+
RequestId: "RequestId",
19+
}
1720

1821
func newJobTest() *job {
1922
mockMessageHandler := &MockMessageHandler{}
@@ -119,14 +122,36 @@ func TestExecuteInNotInitialState(t *testing.T) {
119122
}
120123

121124
func TestExecuteWithProcessError(t *testing.T) {
125+
wg := &sync.WaitGroup{}
126+
127+
errPayload := mockActionResultPayload
128+
errPayload.IsSuccessful = true
129+
errPayload.FailureMessage = "Process Error"
130+
131+
testServer := httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
132+
res.WriteHeader(http.StatusAccepted)
133+
134+
actionResult := &runbook.ActionResultPayload{}
135+
body, _ := ioutil.ReadAll(req.Body)
136+
json.Unmarshal(body, actionResult)
137+
138+
assert.Equal(t, errPayload, actionResult)
139+
assert.Equal(t, "GenieKey "+mockApiKey, req.Header.Get("Authorization"))
140+
wg.Done()
141+
}))
142+
defer testServer.Close()
122143

123144
sqsJob := newJobTest()
145+
sqsJob.baseUrl = testServer.URL
124146

125147
sqsJob.messageHandler.(*MockMessageHandler).HandleFunc = func(message sqs.Message) (payload *runbook.ActionResultPayload, e error) {
126-
return nil, errors.New("Process Error")
148+
return errPayload, errors.New("Process Error")
127149
}
128150

151+
wg.Add(1)
129152
err := sqsJob.Execute()
153+
154+
wg.Wait()
130155
assert.NotNil(t, err)
131156

132157
expectedErr := errors.Errorf("Message[%s] could not be processed: %s", sqsJob.Id(), "Process Error")

queue/message.go

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,32 @@ func (mh *messageHandler) Handle(message sqs.Message) (*runbook.ActionResultPayl
3939
return nil, err
4040
}
4141

42-
entityId := queuePayload.Entity.Id
43-
entityType := queuePayload.Entity.Type
44-
4542
actionType := queuePayload.ActionType
46-
4743
action := queuePayload.MappedAction.Name
4844
if action == "" {
4945
action = queuePayload.Action
5046
}
5147
if action == "" {
52-
return nil, errors.Errorf("SQS message with entityId[%s] does not contain action property.", entityId)
53-
}
54-
55-
mappedAction, ok := mh.actionSpecs.ActionMappings[conf.ActionName(action)]
56-
if !ok {
57-
return nil, errors.Errorf("There is no mapped action found for action[%s]. SQS message with entityId[%s] will be ignored.", action, entityId)
58-
}
59-
60-
if mappedAction.Type != actionType {
61-
return nil, errors.Errorf("The mapped action found for action[%s] with type[%s] but action is coming with type[%s]. SQS message with entityId[%s] will be ignored.",
62-
action, mappedAction.Type, actionType, entityId)
48+
return nil, errors.Errorf("SQS message does not contain action property.")
6349
}
6450

6551
result := &runbook.ActionResultPayload{
66-
EntityId: entityId,
67-
EntityType: entityType,
52+
EntityId: queuePayload.Entity.Id,
53+
EntityType: queuePayload.Entity.Type,
6854
Action: action,
6955
ActionType: actionType,
7056
RequestId: queuePayload.RequestId,
7157
}
7258

59+
mappedAction, err := mh.resolveMappedAction(action, actionType)
60+
if err != nil {
61+
result.IsSuccessful = false
62+
result.FailureMessage = err.Error()
63+
return result, err
64+
}
65+
7366
start := time.Now()
74-
executionResult, callbackContext, err := mh.execute(&mappedAction, &message)
67+
executionResult, callbackContext, err := mh.execute(mappedAction, &message)
7568
took := time.Since(start)
7669

7770
result.CallbackContext = callbackContext
@@ -80,22 +73,22 @@ func (mh *messageHandler) Handle(message sqs.Message) (*runbook.ActionResultPayl
8073
case *runbook.ExecError:
8174
result.IsSuccessful = false
8275
result.FailureMessage = fmt.Sprintf("Err: %s, Stderr: %s", err.Error(), err.Stderr)
83-
logrus.Debugf("Action[%s] execution of message[%s] with entityId[%s] failed: %s Stderr: %s", action, *message.MessageId, entityId, err.Error(), err.Stderr)
76+
logrus.Debugf("Action[%s] execution of message[%s] failed: %s Stderr: %s", action, *message.MessageId, err.Error(), err.Stderr)
8477
case nil:
8578
result.IsSuccessful = true
8679
if !queuePayload.DiscardScriptResponse && queuePayload.ActionType == HttpActionType {
8780
httpResult := &runbook.HttpResponse{}
8881
err := json.Unmarshal([]byte(executionResult), httpResult)
8982
if err != nil {
9083
result.IsSuccessful = false
91-
logrus.Debugf("Http Action[%s] execution of message[%s] with entityId[%s] failed, could not parse http response fields: %s, error: %s",
92-
action, *message.MessageId, entityId, executionResult, err.Error())
84+
logrus.Debugf("Http Action[%s] execution of message[%s] failed, could not parse http response fields: %s, error: %s",
85+
action, *message.MessageId, executionResult, err.Error())
9386
result.FailureMessage = "Could not parse http response fields: " + executionResult
9487
} else {
9588
result.HttpResponse = httpResult
9689
}
9790
}
98-
logrus.Debugf("Action[%s] execution of message[%s] with entityId[%s] has been completed and it took %f seconds.", action, *message.MessageId, entityId, took.Seconds())
91+
logrus.Debugf("Action[%s] execution of message[%s] has been completed and it took %f seconds.", action, *message.MessageId, took.Seconds())
9992

10093
default:
10194
return nil, err
@@ -104,6 +97,24 @@ func (mh *messageHandler) Handle(message sqs.Message) (*runbook.ActionResultPayl
10497
return result, nil
10598
}
10699

100+
func (mh *messageHandler) resolveMappedAction(action string, actionType string) (*conf.MappedAction, error) {
101+
mappedAction, ok := mh.actionSpecs.ActionMappings[conf.ActionName(action)]
102+
103+
if !ok {
104+
failureMessage := fmt.Sprintf("No mapped action is configured for requested action[%s]. "+
105+
"The request will be ignored.", action)
106+
return nil, errors.Errorf(failureMessage)
107+
}
108+
109+
if mappedAction.Type != actionType {
110+
failureMessage := fmt.Sprintf("The type[%s] of the mapped action[%s] is not compatible with requested type[%s]. "+
111+
"The request will be ignored.", mappedAction.Type, action, actionType)
112+
return nil, errors.Errorf(failureMessage)
113+
}
114+
115+
return &mappedAction, nil
116+
}
117+
107118
func (mh *messageHandler) execute(mappedAction *conf.MappedAction, message *sqs.Message) (string, string, error) {
108119

109120
sourceType := mappedAction.SourceType

queue/message_test.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,21 @@ func testProcessMappedActionNotFound(t *testing.T) {
126126

127127
runbook.ExecuteFunc = mockExecute
128128

129-
body := `{"action":"Ack"}`
129+
body := `{"actionType":"custom", "action":"Ack", "requestId": "RequestId"}`
130130
message := sqs.Message{Body: &body}
131131
messageHandler := NewMessageHandler(nil, mockActionSpecs, mockActionLoggers)
132132

133-
_, err := messageHandler.Handle(message)
134-
expectedErr := errors.New("There is no mapped action found for action[Ack]. SQS message with entityId[] will be ignored.")
133+
result, err := messageHandler.Handle(message)
134+
expectedErr := errors.New("No mapped action is configured for requested action[Ack]. The request will be ignored.")
135+
expectedResult := &runbook.ActionResultPayload{
136+
Action: "Ack",
137+
ActionType: "custom",
138+
RequestId: "RequestId",
139+
IsSuccessful: false,
140+
FailureMessage: "No mapped action is configured for requested action[Ack]. The request will be ignored.",
141+
}
135142
assert.EqualError(t, err, expectedErr.Error())
143+
assert.Equal(t, result, expectedResult)
136144
}
137145

138146
func testProcessActionTypeNotMatched(t *testing.T) {
@@ -142,10 +150,19 @@ func testProcessActionTypeNotMatched(t *testing.T) {
142150
message := sqs.Message{Body: &body}
143151
messageHandler := NewMessageHandler(nil, mockActionSpecs, mockActionLoggers)
144152

145-
_, err := messageHandler.Handle(message)
146-
expectedErr := errors.New("The mapped action found for action[Close] with type[custom] but action is coming with type[http]. " +
147-
"SQS message with entityId[] will be ignored.")
153+
result, err := messageHandler.Handle(message)
154+
expectedErr := errors.New("The type[custom] of the mapped action[Close] is not compatible with requested type[http]. " +
155+
"The request will be ignored.")
156+
expectedResult := &runbook.ActionResultPayload{
157+
Action: "Close",
158+
ActionType: "http",
159+
RequestId: "RequestId",
160+
IsSuccessful: false,
161+
FailureMessage: "The type[custom] of the mapped action[Close] is not compatible with requested type[http]. " +
162+
"The request will be ignored.",
163+
}
148164
assert.EqualError(t, err, expectedErr.Error())
165+
assert.Equal(t, result, expectedResult)
149166
}
150167

151168
func testProcessFieldMissing(t *testing.T) {
@@ -157,7 +174,7 @@ func testProcessFieldMissing(t *testing.T) {
157174
messageHandler := NewMessageHandler(nil, mockActionSpecs, mockActionLoggers)
158175

159176
_, err := messageHandler.Handle(message)
160-
expectedErr := errors.New("SQS message with entityId[] does not contain action property.")
177+
expectedErr := errors.New("SQS message does not contain action property.")
161178
assert.EqualError(t, err, expectedErr.Error())
162179
}
163180

0 commit comments

Comments
 (0)