INFRA-3012 : Houston topic changes according to new construct (#415)

* INFRA-3012 : Houston title changes according to new construct

* INFRA-3012 : add titkle change for resolve and duplicate case

* INFRA-3012 : Failing tests fix

* INFRA-3012 : Added migration script for backfilling
This commit is contained in:
Vijay Joshi
2024-04-26 14:52:12 +05:30
committed by GitHub
parent bd5e479e0f
commit 29f0c7bacc
12 changed files with 290 additions and 74 deletions

View File

@@ -0,0 +1,15 @@
BEGIN TRANSACTION;
INSERT INTO incident_products (incident_entity_id, product_entity_id)
SELECT i.id, 9
FROM incident i
WHERE NOT EXISTS (
SELECT 1
FROM incident_products ip
WHERE ip.incident_entity_id = i.id
);
UPDATE incident set reporting_team_id = 85 where reporting_team_id is NULL;
COMMIT;

View File

@@ -8,6 +8,8 @@ import (
"houston/model/severity"
"houston/model/team"
"houston/pkg/slackbot"
"houston/service/incident/impl"
slackService "houston/service/slack"
"github.com/slack-go/slack"
"github.com/slack-go/slack/socketmode"
@@ -15,21 +17,22 @@ import (
)
type IncidentUpdateTitleAction struct {
client *socketmode.Client
client *socketmode.Client
incidentService *incident.Repository
teamService *team.Repository
severityService *severity.Repository
slackbotClient *slackbot.Client
slackService slackService.ISlackService
}
func NewIncidentUpdateTitleAction(client *socketmode.Client, incidentService *incident.Repository, teamService *team.Repository, severityService *severity.Repository, slackbotClient *slackbot.Client) *IncidentUpdateTitleAction {
func NewIncidentUpdateTitleAction(client *socketmode.Client, incidentService *incident.Repository, teamService *team.Repository, severityService *severity.Repository, slackbotClient *slackbot.Client, service slackService.ISlackService) *IncidentUpdateTitleAction {
return &IncidentUpdateTitleAction{
client: client,
incidentService: incidentService,
teamService: teamService,
severityService: severityService,
slackbotClient: slackbotClient,
slackService: service,
}
}
@@ -83,25 +86,13 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac
zap.String("user_id", user.ID), zap.Error(err))
return
}
msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `houston set title to %s`", user.ID, incidentEntity.Title), false)
msgOption := slack.MsgOptionText(fmt.Sprintf("<@%s> *>* `houston set title to %s`", user.ID, incidentEntity.Title), false)
_, _, errMessage := itp.client.PostMessage(callback.View.PrivateMetadata, msgOption)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateTitle", zap.Error(errMessage))
return
}
result, err := itp.incidentService.FindIncidentSeverityTeamJoin(incidentEntity.SlackChannel)
if err != nil {
logger.Error("query failed for FindIncidentSeverityTeamJoin", zap.Error(errMessage))
return
}
msgOption = slack.MsgOptionText(fmt.Sprintf("set the channel topic: %s : %s %s | %s", result.TeamName, result.SeverityName, incidentEntity.IncidentName, incidentEntity.Title), false)
_, _, errMessage = itp.client.PostMessage(callback.View.PrivateMetadata, msgOption)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateTitle", zap.Error(errMessage))
return
}
severityEntity, err := itp.severityService.FindSeverityById(incidentEntity.SeverityId)
if err != nil {
logger.Error("error in fetching severity in incident update type action", zap.String("channel", incidentEntity.SlackChannel),
@@ -113,6 +104,17 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac
return
}
statusEntity, err := itp.incidentService.FindIncidentStatusById(incidentEntity.Status)
if err != nil {
logger.Error("error in fetching status in incident update type action", zap.String("channel", incidentEntity.SlackChannel),
zap.Uint("incident_id", incidentEntity.ID), zap.Error(err))
return
} else if statusEntity == nil {
logger.Info("status not found in incident update type action", zap.String("channel", incidentEntity.SlackChannel),
zap.Uint("incident_id", incidentEntity.ID))
return
}
teamEntity, err := itp.teamService.FindTeamById(incidentEntity.TeamId)
if err != nil {
logger.Error("FindTeamEntityById error",
@@ -126,8 +128,32 @@ func (itp *IncidentUpdateTitleAction) IncidentUpdateTitle(callback slack.Interac
return
}
topic := fmt.Sprintf("%s-%s(%s) Incident-%d | %s", teamEntity.Name, severityEntity.Name, severityEntity.Description, incidentEntity.ID, incidentEntity.Title)
itp.slackbotClient.SetChannelTopic(callback.View.PrivateMetadata, topic)
productNames := make([]string, 0)
for _, product := range incidentEntity.Products {
productNames = append(productNames, product.Name)
}
channelTopic := impl.ChannelTopic{
ProductNames: productNames,
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: teamEntity.Name,
SeverityName: severityEntity.Name,
StatusName: statusEntity.Name,
Title: incidentEntity.Title,
}
msgOption = slack.MsgOptionText(fmt.Sprintf("set the channel topic: %s", channelTopic.String()), false)
_, _, errMessage = itp.client.PostMessage(callback.View.PrivateMetadata, msgOption)
if errMessage != nil {
logger.Error("post response failed for IncidentUpdateTitle", zap.Error(errMessage))
return
}
err = itp.slackService.SetTopicOfConversationByChannelId(incidentEntity.SlackChannel, incidentEntity.IncidentName, channelTopic.String())
if err != nil {
logger.Error("error in setting channel topic", zap.Error(err))
return
}
var payload interface{}
itp.client.Ack(*request, payload)

View File

@@ -92,7 +92,7 @@ func NewBlockActionProcessor(
incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, incidentRepository,
severityService, teamService, slackbotClient, incidentServiceV2),
incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, incidentRepository,
teamService, severityService, slackbotClient),
teamService, severityService, slackbotClient, slackService),
incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, incidentRepository),
incidentDuplicateAction: action.NewDuplicateIncidentProcessor(socketModeClient, incidentRepository,
tagService, teamService, severityService, incidentServiceV2),
@@ -266,7 +266,7 @@ func NewViewSubmissionProcessor(
updateIncidentAction: action.NewIncidentUpdateAction(socketModeClient, incidentRepository,
tagService, teamService, severityService, incidentServiceV2),
incidentUpdateTitleAction: action.NewIncidentUpdateTitleAction(socketModeClient, incidentRepository,
teamService, severityService, slackbotClient),
teamService, severityService, slackbotClient, slackService),
incidentUpdateDescriptionAction: action.NewIncidentUpdateDescriptionAction(socketModeClient, incidentRepository),
incidentUpdateSeverityAction: action.NewIncidentUpdateSeverityAction(socketModeClient, incidentRepository,
severityService, teamService, slackbotClient, incidentServiceV2),

View File

@@ -309,7 +309,7 @@ func (r *Repository) GetOpenIncidents(limit int) (*[]IncidentSeverityTeamDTO, er
func (r *Repository) FindIncidentByChannelId(channelId string) (*IncidentEntity, error) {
var incidentEntity IncidentEntity
result := r.gormClient.Preload("Products").Find(&incidentEntity, "slack_channel = ?", channelId)
result := r.gormClient.Preload("Products").Preload("ReportingTeam").Find(&incidentEntity, "slack_channel = ?", channelId)
if result.Error != nil {
return nil, result.Error
}
@@ -324,7 +324,7 @@ func (r *Repository) FindIncidentByChannelId(channelId string) (*IncidentEntity,
func (r *Repository) FindIncidentById(Id uint) (*IncidentEntity, error) {
var incidentEntity IncidentEntity
result := r.gormClient.Preload("Products").Find(&incidentEntity, "id = ?", Id)
result := r.gormClient.Preload("Products").Preload("ReportingTeam").Find(&incidentEntity, "id = ?", Id)
if result.Error != nil {
return nil, result.Error
}

View File

@@ -0,0 +1,29 @@
package impl
import (
"fmt"
"strings"
)
type ChannelTopic struct {
ProductNames []string
ReportingTeamName string
ResponderTeamName string
SeverityName string
StatusName string
Title string
}
func (td *ChannelTopic) String() string {
var productNameCommaSeparated string
if len(td.ProductNames) > 1 {
productNameCommaSeparated = fmt.Sprintf(strings.Join(td.ProductNames[:len(td.ProductNames)-1], ", ") + " & " + td.ProductNames[len(td.ProductNames)-1])
} else if len(td.ProductNames) == 1 {
productNameCommaSeparated = td.ProductNames[0]
}
return fmt.Sprintf(
"%s || %s (%s) || %s -> %s || %s",
productNameCommaSeparated, td.SeverityName, td.StatusName,
td.ReportingTeamName, td.ResponderTeamName, td.Title,
)
}

View File

@@ -12,6 +12,7 @@ import (
"houston/mocks"
"houston/model/incident"
"houston/model/incident_channel"
"houston/model/product"
"houston/model/severity"
"houston/model/team"
teamUserModel "houston/model/teamUser"
@@ -38,6 +39,7 @@ type IncidentServiceSuite struct {
calendarService mocks.ICalendarServiceMock
rcaService mocks.IRcaServiceMock
severityService mocks.ISeverityServiceMock
teamServiceV2 mocks.ITeamServiceV2Mock
mockDirectory string
mockPngName string
mockCsvName string
@@ -122,6 +124,10 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() {
suite.teamUserService.GetTeamUsersForGivenSeverityMock.Return([]teamUserModel.TeamUserDTO{tu}, nil)
suite.teamUserService.GetTeamUsersWithMinimumSeverityIdLessThanOrEqualToGivenSeverityMock.Return([]teamUserModel.TeamUserDTO{tu}, nil)
suite.teamServiceV2.GetTeamByIdMock.Return(GetMockTeamWithId(1), nil)
suite.severityService.FindSeverityByIdMock.Return(GetMockSeverityDTOWitId(mockIncident.SeverityId), nil)
suite.slackService.SetTopicOfConversationByChannelIdMock.Return(nil)
suite.incidentRepository.UpdateIncidentWithAssociationsMock.Return(nil)
_, err := suite.incidentService.UpdateIncident(
service.UpdateIncidentRequest{
Id: suite.mockIncidentId,
@@ -129,6 +135,7 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_Success() {
SeverityId: "3",
TeamId: "2",
MetaData: mockMetaData,
ProductIDs: []uint{1, 2},
},
suite.mockUserEmail,
)
@@ -310,6 +317,8 @@ func (suite *IncidentServiceSuite) Test_UpdateIncident_SlackError() {
suite.slackService.UpdateMessageWithAttachmentsMock.Return(errors.New("Could not update message"))
suite.slackService.SetTopicOfConversationByChannelIdMock.Return(errors.New("Could not set topic of conversation"))
_, err := suite.incidentService.UpdateIncident(
service.UpdateIncidentRequest{
Id: suite.mockIncidentId,
@@ -378,6 +387,7 @@ func GetMockIncident() *incident.IncidentEntity {
RCA: "",
ConferenceId: "",
ConferenceLink: "",
Products: make([]product.ProductEntity, 1),
}
}
@@ -418,6 +428,15 @@ func GetMockSeverityWithId(severityId uint) *severity.SeverityEntity {
}
}
func GetMockSeverityDTOWitId(severityId uint) *severity.SeverityDTO {
return &severity.SeverityDTO{
ID: severityId,
Name: "Mock Severity",
Description: "Mock Description",
SlackUserIds: pq.StringArray{"1", "2"},
}
}
func GetMockStatusWithId(statusId uint) *incident.IncidentStatusEntity {
return &incident.IncidentStatusEntity{
Model: gorm.Model{
@@ -498,6 +517,7 @@ func (suite *IncidentServiceSuite) SetupTest() {
suite.updatedTeamId = 2
suite.teamUserService = *mocks.NewITeamUserServiceMock(suite.T())
suite.severityService = *mocks.NewISeverityServiceMock(suite.T())
suite.teamServiceV2 = *mocks.NewITeamServiceV2Mock(suite.T())
suite.incidentService = &IncidentServiceV2{
db: nil,
slackService: &suite.slackService,
@@ -513,6 +533,7 @@ func (suite *IncidentServiceSuite) SetupTest() {
rcaService: &suite.rcaService,
teamUserService: &suite.teamUserService,
severityService: &suite.severityService,
teamServiceV2: &suite.teamServiceV2,
}
suite.mockDirectory = "test_file"

View File

@@ -156,7 +156,7 @@ const logTag = "[create-incident]"
const updateLogTag = "[update-incident-v2]"
const resolveLogTag = "[resolve-incident]"
const updateSeveritySlackActionCount = 6
const updateStatusSlackActionCount = 2
const updateStatusSlackActionCount = 3
const updateTeamSlackActionCount = 5
/*
@@ -1480,8 +1480,17 @@ func (i *IncidentServiceV2) UpdateSeverityWorkflow(
})
go util.ExecuteConcurrentAction(&waitGroup, func() {
err := i.slackService.SetChannelTopicByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName, teamEntity, severityEntity, incidentEntity,
channelTopic := ChannelTopic{
ProductNames: getProductNamesFromProducts(incidentEntity.Products),
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: teamEntity.Name,
SeverityName: severityEntity.Name,
StatusName: incidentStatusEntity.Name,
Title: incidentEntity.Title,
}
err := i.slackService.SetTopicOfConversationByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName,
channelTopic.String(),
)
if err != nil {
logger.Error(
@@ -1630,6 +1639,28 @@ func (i *IncidentServiceV2) UpdateStatusWorkflow(
processUpdateMessage(incidentEntity, teamEntity, severityEntity, incidentStatus, incidentChannels, i)
})
go util.ExecuteConcurrentAction(&waitGroup, func() {
channelTopic := ChannelTopic{
ProductNames: getProductNamesFromProducts(incidentEntity.Products),
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: teamEntity.Name,
SeverityName: severityEntity.Name,
StatusName: incidentStatus.Name,
Title: incidentEntity.Title,
}
err := i.slackService.SetTopicOfConversationByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName,
channelTopic.String(),
)
if err != nil {
logger.Error(
fmt.Sprintf("%s %d error while setting channel topic", updateLogTag, incidentEntity.TeamId),
zap.Error(err),
)
slackErrors = append(slackErrors, err)
}
})
waitGroup.Wait()
if slackErrors != nil && len(slackErrors) != 0 {
return slackErrors[0]
@@ -1843,19 +1874,24 @@ func (i *IncidentServiceV2) UpdateTeamIdWorkflow(
slackErrors = append(slackErrors, err)
}
channelTopic := ChannelTopic{
ProductNames: getProductNamesFromProducts(incidentEntity.Products),
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: teamEntity.Name,
SeverityName: severityEntity.Name,
StatusName: incidentStatus.Name,
Title: incidentEntity.Title,
}
var waitGroup sync.WaitGroup
waitGroup.Add(updateTeamSlackActionCount)
go util.ExecuteConcurrentAction(&waitGroup, func() {
txt := fmt.Sprintf(
"<@%s> *>* set the channel topic: *%s · %s (%s) %s* | %s",
"<@%s> *>* set the channel topic: %s",
userId,
teamEntity.Name,
severityEntity.Name,
severityEntity.Description,
incidentEntity.IncidentName,
incidentEntity.Title,
channelTopic.String(),
)
att := slackUtil.Attachment{
Text: txt,
@@ -1905,8 +1941,9 @@ func (i *IncidentServiceV2) UpdateTeamIdWorkflow(
})
go util.ExecuteConcurrentAction(&waitGroup, func() {
err := i.slackService.SetChannelTopicByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName, teamEntity, severityEntity, incidentEntity,
err := i.slackService.SetTopicOfConversationByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName,
channelTopic.String(),
)
if err != nil {
logger.Error(
@@ -1935,7 +1972,7 @@ func (i *IncidentServiceV2) UpdateProductIdWorkflow(
) error {
var slackErrors []error
var waitGroup sync.WaitGroup
waitGroup.Add(2)
waitGroup.Add(3)
incidentEntity, err := i.incidentRepository.FindIncidentById(incidentID)
if err != nil {
@@ -1943,10 +1980,7 @@ func (i *IncidentServiceV2) UpdateProductIdWorkflow(
return err
}
var productNames []string
for _, p := range incidentEntity.Products {
productNames = append(productNames, p.Name)
}
productNames := getProductNamesFromProducts(incidentEntity.Products)
go util.ExecuteConcurrentAction(&waitGroup, func() {
txt := fmt.Sprintf(
@@ -1967,6 +2001,28 @@ func (i *IncidentServiceV2) UpdateProductIdWorkflow(
processUpdateMessage(incidentEntity, teamEntity, severityEntity, incidentStatus, incidentChannels, i)
})
go util.ExecuteConcurrentAction(&waitGroup, func() {
channelTopic := ChannelTopic{
ProductNames: productNames,
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: teamEntity.Name,
SeverityName: severityEntity.Name,
StatusName: incidentStatus.Name,
Title: incidentEntity.Title,
}
err := i.slackService.SetTopicOfConversationByChannelId(
incidentEntity.SlackChannel, incidentEntity.IncidentName,
channelTopic.String(),
)
if err != nil {
logger.Error(
fmt.Sprintf("%s %d error while setting channel topic", updateLogTag, incidentEntity.TeamId),
zap.Error(err),
)
slackErrors = append(slackErrors, err)
}
})
waitGroup.Wait()
if slackErrors != nil && len(slackErrors) != 0 {
return slackErrors[0]
@@ -2214,3 +2270,11 @@ func (i *IncidentServiceV2) SendAlert(incidentEntity *incident.IncidentEntity) {
logger.Error(fmt.Sprintf("Error occurred while sending alert for incident: %d", incidentEntity.ID))
}
}
func getProductNamesFromProducts(products []product.ProductEntity) []string {
var productNames []string
for _, product := range products {
productNames = append(productNames, product.Name)
}
return productNames
}

View File

@@ -23,7 +23,7 @@ import (
"time"
)
const postUpdateResolveStatusActionCount = 3
const postUpdateResolveStatusActionCount = 4
func (i *IncidentServiceV2) DuplicateUpdateIncidentStatus(duplicateOfID uint, userID string, incidentEntity *incident.IncidentEntity) error {
channelID := incidentEntity.SlackChannel
@@ -53,7 +53,7 @@ func (i *IncidentServiceV2) DuplicateUpdateIncidentStatus(duplicateOfID uint, us
return customErrors.NewDataAccessError(fmt.Sprintf("Failed to update incident with id %d", incidentId))
}
i.DuplicateUpdateStatusWorkFlow(channelID, originalIncidentChannel, incidentEntity.SeverityId)
i.DuplicateUpdateStatusWorkFlow(channelID, originalIncidentChannel, incidentEntity)
return nil
}
func (i *IncidentServiceV2) validateDuplicateIdAndGetChannelId(duplicateOfID uint, incidentId uint) (string, error) {
@@ -70,11 +70,11 @@ func (i *IncidentServiceV2) validateDuplicateIdAndGetChannelId(duplicateOfID uin
}
return originalIncident.SlackChannel, nil
}
func (i *IncidentServiceV2) DuplicateUpdateStatusWorkFlow(currentChannel, originalIncidentChannel string, severityId uint) {
func (i *IncidentServiceV2) DuplicateUpdateStatusWorkFlow(currentChannel, originalIncidentChannel string, incidentEntity *incident.IncidentEntity) {
var waitGroup sync.WaitGroup
waitGroup.Add(1)
go util.ExecuteConcurrentAction(&waitGroup, func() {
msg, err := houstonSlackUtil.GetArchivalTimeOfIncidentChannel(incident.Duplicated, int(severityId))
msg, err := houstonSlackUtil.GetArchivalTimeOfIncidentChannel(incident.Duplicated, int(incidentEntity.SeverityId))
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to get archiving time for incident channel %s", updateLogTag, currentChannel), zap.Error(err))
metrics.PublishHoustonFlowFailureMetrics(DUPLICATE_INCIDENT, err.Error())
@@ -94,6 +94,36 @@ func (i *IncidentServiceV2) DuplicateUpdateStatusWorkFlow(currentChannel, origin
metrics.PublishHoustonFlowFailureMetrics(DUPLICATE_INCIDENT, err.Error())
}
})
waitGroup.Add(1)
go util.ExecuteConcurrentAction(&waitGroup, func() {
responderTeam, err := i.teamServiceV2.GetTeamById(incidentEntity.TeamId)
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to get team with id %d", updateLogTag, incidentEntity.TeamId), zap.Error(err))
metrics.PublishHoustonFlowFailureMetrics(DUPLICATE_INCIDENT, err.Error())
return
}
severity, err := i.severityService.FindSeverityById(incidentEntity.SeverityId)
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to get severity with id %d", updateLogTag, incidentEntity.SeverityId), zap.Error(err))
metrics.PublishHoustonFlowFailureMetrics(DUPLICATE_INCIDENT, err.Error())
return
}
channelTopic := ChannelTopic{
ProductNames: getProductNamesFromProducts(incidentEntity.Products),
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: responderTeam.Name,
SeverityName: severity.Name,
StatusName: incident.Duplicated,
Title: incidentEntity.Title,
}
err = i.slackService.SetTopicOfConversationByChannelId(currentChannel, incidentEntity.IncidentName, channelTopic.String())
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to set channel topic for channel %s", updateLogTag, currentChannel), zap.Error(err))
metrics.PublishHoustonFlowFailureMetrics(DUPLICATE_INCIDENT, err.Error())
}
})
waitGroup.Wait()
}
@@ -714,6 +744,35 @@ func (i *IncidentServiceV2) postUpdateResolveStatusFlow(incidentEntity *incident
}
})
go util.ExecuteConcurrentAction(&waitGroup, func() {
responderTeam, err := i.teamServiceV2.GetTeamById(incidentEntity.TeamId)
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to get team with id %d", updateLogTag, incidentEntity.TeamId), zap.Error(err))
postResolveErrors.AddErrors(err)
return
}
severity, err := i.severityService.FindSeverityById(incidentEntity.SeverityId)
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to get severity with id %d", updateLogTag, incidentEntity.SeverityId), zap.Error(err))
postResolveErrors.AddErrors(err)
return
}
channelTopic := ChannelTopic{
ProductNames: getProductNamesFromProducts(incidentEntity.Products),
ReportingTeamName: incidentEntity.ReportingTeam.Name,
ResponderTeamName: responderTeam.Name,
SeverityName: severity.Name,
StatusName: incident.Resolved,
Title: incidentEntity.Title,
}
err = i.slackService.SetTopicOfConversationByChannelId(incidentEntity.SlackChannel, incidentEntity.IncidentName, channelTopic.String())
if err != nil {
logger.Error(fmt.Sprintf("%s Failed to set channel topic for channel %s", updateLogTag, incidentEntity.SlackChannel), zap.Error(err))
postResolveErrors.AddErrors(err)
}
})
go i.DeleteConferenceEvent(incidentEntity)
go i.processIncidentRCAFlow(incidentEntity)

View File

@@ -67,6 +67,9 @@ func (suite *IncidentServiceSuite) TestDuplicateUpdateIncidentStatus_Success() {
suite.incidentRepository.FindIncidentByIdMock.When(mockOriginalIncident.ID).Then(mockOriginalIncident, nil)
suite.incidentRepository.UpdateIncidentMock.When(mockCurrentIncident).Then(nil)
suite.slackService.PostMessageByChannelIDMock.Return("", nil)
suite.teamServiceV2.GetTeamByIdMock.Return(GetMockTeamWithId(1), nil)
suite.severityService.FindSeverityByIdMock.Return(GetMockSeverityDTOWitId(mockCurrentIncident.SeverityId), nil)
suite.slackService.SetTopicOfConversationByChannelIdMock.Return(nil)
err := suite.incidentService.DuplicateUpdateIncidentStatus(mockOriginalIncident.ID, "userID", mockCurrentIncident)
suite.NoError(err)
}
@@ -546,6 +549,9 @@ func (suite *IncidentServiceSuite) TestResolveIncident_PostResolveFlowErrorCase(
suite.slackService.UpdateMessageWithAttachmentsMock.Return(errors.New("Slack Error"))
suite.calendarService.DeleteEventMock.Return(nil)
suite.rcaService.SendConversationDataForGeneratingRCAMock.Return(nil)
suite.teamServiceV2.GetTeamByIdMock.Return(GetMockTeamWithId(1), nil)
suite.severityService.FindSeverityByIdMock.Return(GetMockSeverityDTOWitId(mockIncident.SeverityId), nil)
suite.slackService.SetTopicOfConversationByChannelIdMock.Return(nil)
err := suite.incidentService.ResolveIncident(sampleRequest, "")
suite.Error(err, "service must throw error")
}
@@ -586,6 +592,9 @@ func (suite *IncidentServiceSuite) TestResolveIncident_HappyFlow() {
suite.slackService.UpdateMessageWithAttachmentsMock.Return(nil)
suite.calendarService.DeleteEventMock.Return(nil)
suite.rcaService.SendConversationDataForGeneratingRCAMock.Return(nil)
suite.teamServiceV2.GetTeamByIdMock.Return(GetMockTeamWithId(1), nil)
suite.severityService.FindSeverityByIdMock.Return(GetMockSeverityDTOWitId(mockIncident.SeverityId), nil)
suite.slackService.SetTopicOfConversationByChannelIdMock.Return(nil)
err := suite.incidentService.ResolveIncident(sampleRequest, "")
suite.NoError(err, "No error must be thrown")
}

View File

@@ -14,6 +14,7 @@ import (
"houston/model/team"
user2 "houston/model/user"
incidentService "houston/service/incident"
incidentServiceImpl "houston/service/incident/impl"
"houston/service/products"
"houston/service/productsTeams"
incidentRequest "houston/service/request/incident"
@@ -222,7 +223,7 @@ func (i *incidentOrchestratorImpl) CreateIncident(
return nil, err
}
err = i.setChannelTopic(slackChannel, channelTopic, incidentEntity)
err = i.setChannelTopic(slackChannel, channelTopic)
if err != nil {
return nil, err
}
@@ -318,13 +319,13 @@ func (i *incidentOrchestratorImpl) getDefaultTeam() (*team.TeamDTO, error) {
func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
createIncRequest *incidentRequest.CreateIncidentRequestV3,
) (*incident.CreateIncidentDTO, *channelTopic, error) {
) (*incident.CreateIncidentDTO, *incidentServiceImpl.ChannelTopic, error) {
var (
createIncidentDTO incident.CreateIncidentDTO
err error
wg sync.WaitGroup
mutex sync.Mutex
channelTopic = &channelTopic{}
channelTopic = &incidentServiceImpl.ChannelTopic{}
)
wg.Add(5)
@@ -337,6 +338,7 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
}
mutex.Lock()
createIncidentDTO.ReportingTeamID = &reportingTeam.ID
channelTopic.ReportingTeamName = reportingTeam.Name
mutex.Unlock()
}()
@@ -347,8 +349,8 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
return
}
mutex.Lock()
channelTopic.teamName = responderTeam.Name
createIncidentDTO.TeamId = fmt.Sprintf("%d", responderTeam.ID)
channelTopic.ResponderTeamName = responderTeam.Name
mutex.Unlock()
}()
@@ -359,9 +361,8 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
return
}
mutex.Lock()
channelTopic.severityName = severityDTO.Name
channelTopic.severityDescription = severityDTO.Description
createIncidentDTO.Severity = fmt.Sprintf("%d", severityDTO.ID)
channelTopic.SeverityName = severityDTO.Name
mutex.Unlock()
}()
@@ -375,8 +376,13 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
err = fmt.Errorf("error in fetching product details")
return
}
var productNames []string
for _, product := range productDTOs {
productNames = append(productNames, product.ProductName)
}
mutex.Lock()
createIncidentDTO.ProductIds = createIncRequest.ProductIds
channelTopic.ProductNames = productNames
mutex.Unlock()
}()
@@ -394,8 +400,10 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
}
createIncidentDTO.Title = createIncRequest.Title
channelTopic.Title = createIncRequest.Title
createIncidentDTO.Description = createIncRequest.Description
createIncidentDTO.Status = incident.Investigating
channelTopic.StatusName = string(incident.Investigating)
createIncidentDTO.UpdatedBy = createIncidentDTO.CreatedBy
createIncidentDTO.StartTime = time.Now()
createIncidentDTO.EnableReminder = false
@@ -410,7 +418,7 @@ func (i *incidentOrchestratorImpl) buildCreateIncidentDTO(
func (i *incidentOrchestratorImpl) createIncidentEntityTransactionally(
request *incidentRequest.CreateIncidentRequestV3, tx *gorm.DB,
) (*incident.IncidentEntity, *channelTopic, error) {
) (*incident.IncidentEntity, *incidentServiceImpl.ChannelTopic, error) {
createIncidentDTO, channelTopic, err := i.buildCreateIncidentDTO(request)
if err != nil {
return nil, nil, err
@@ -442,10 +450,8 @@ func (i *incidentOrchestratorImpl) createSlackChannelTransactionally(
}
func (i *incidentOrchestratorImpl) setChannelTopic(
channel *slack2.Channel, channelTopic *channelTopic, incidentEntity *incident.IncidentEntity,
channel *slack2.Channel, channelTopic *incidentServiceImpl.ChannelTopic,
) error {
channelTopic.incidentTitle = incidentEntity.Title
channelTopic.incidentID = incidentEntity.ID
err := i.slackService.SetTopicOfConversation(channel, channelTopic.String())
if err != nil {
logger.Error(
@@ -471,25 +477,6 @@ func (i *incidentOrchestratorImpl) updateSlackDetailsIntoIncidentEntity(channel
return nil
}
type channelTopic struct {
teamName string
severityName string
severityDescription string
incidentID uint
incidentTitle string
}
func (td *channelTopic) String() string {
return fmt.Sprintf(
"%s-%s(%s) Incident-%d | %s",
td.teamName,
td.severityName,
td.severityDescription,
td.incidentID,
td.incidentTitle,
)
}
type sortListOfTeamDTOByName []team.TeamDTO
func (t sortListOfTeamDTOByName) Len() int {

View File

@@ -178,10 +178,13 @@ func (s *SlackService) SetChannelTopic(
}
func (s *SlackService) SetTopicOfConversation(channel *slack.Channel, topic string) error {
return s.setTopicOfConversation(channel.ID, channel.Name, topic)
return s.SetTopicOfConversationByChannelId(channel.ID, channel.Name, topic)
}
func (s *SlackService) setTopicOfConversation(channelID, channelName string, topic string) error {
func (s *SlackService) SetTopicOfConversationByChannelId(channelID, channelName string, topic string) error {
if len(topic) > channelTopicLengthLimit {
topic = topic[:maxAllowedTopicIndex] + "..."
}
_, err := s.SocketModeClientWrapper.SetTopicOfConversation(channelID, topic)
if err != nil {
e := fmt.Sprintf("%s set topic on slack channel failed", logTag)
@@ -209,7 +212,7 @@ func (s *SlackService) SetChannelTopicByChannelId(
incidentEntity.Title,
)
return s.setTopicOfConversation(channelID, channelName, topic)
return s.SetTopicOfConversationByChannelId(channelID, channelName, topic)
}
func (s *SlackService) GetUserByEmailOrID(userEmailOrSlackID string) (*slack.User, error) {
@@ -666,3 +669,5 @@ const (
)
const userOptionLimit = 200
const channelTopicLengthLimit = 250
const maxAllowedTopicIndex = 247

View File

@@ -35,6 +35,7 @@ type ISlackService interface {
UpdateMessageWithAttachments(channelID string, timestamp string, options slack.Attachment) error
PostMessageWithAttachments(channelID string, attachment slack.Attachment) (string, error)
SetTopicOfConversation(channel *slack.Channel, topic string) error
SetTopicOfConversationByChannelId(channelId, channelName, topic string) error
SetChannelTopicByChannelId(
channelID string,
channelName string,