From c09d827a2d9aee35dc24726315ef06e054838f9e Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Mon, 18 Nov 2024 02:04:08 +0500 Subject: [PATCH 1/6] implement workflow request handler --- db/structs.go | 20 +++++++++---------- handlers/workflow.go | 39 +++++++++++++++++++++++++++++++------ utils/workflow_processor.go | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 utils/workflow_processor.go diff --git a/db/structs.go b/db/structs.go index de784ef59..00e3adebe 100644 --- a/db/structs.go +++ b/db/structs.go @@ -920,14 +920,14 @@ const ( ) type WfProcessingMap struct { - ID uint `gorm:"primaryKey;autoIncrement" json:"id"` - Type string `gorm:"index;not null" json:"type"` - ProcessKey string `gorm:"index;not null" json:"process_key"` - RequiresProcessing bool `gorm:"default:false" json:"requires_processing"` - HandlerFunc string `json:"handler_func,omitempty"` - Config JSONB `gorm:"type:jsonb" json:"config,omitempty"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID uint `gorm:"primaryKey;autoIncrement" json:"id"` + Type string `gorm:"index;not null" json:"type"` + ProcessKey string `gorm:"index;not null" json:"process_key"` + RequiresProcessing bool `gorm:"default:false" json:"requires_processing"` + HandlerFunc string `json:"handler_func,omitempty"` + Config PropertyMap `gorm:"type:jsonb" json:"config,omitempty"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type WfRequest struct { @@ -938,8 +938,8 @@ type WfRequest struct { Action string `gorm:"index" json:"action"` Status WfRequestStatus `json:"status"` ProjectID string `json:"project_id,omitempty"` - RequestData JSONB `gorm:"type:jsonb" json:"request_data"` - ResponseData JSONB `gorm:"type:jsonb" json:"response_data,omitempty"` + RequestData PropertyMap `gorm:"type:jsonb" json:"request_data"` + ResponseData PropertyMap `gorm:"type:jsonb" json:"response_data,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } diff --git a/handlers/workflow.go b/handlers/workflow.go index 22253e878..267396933 100644 --- a/handlers/workflow.go +++ b/handlers/workflow.go @@ -1,8 +1,9 @@ package handlers import ( - "fmt" + "encoding/json" "github.com/stakwork/sphinx-tribes/db" + "github.com/stakwork/sphinx-tribes/utils" "io" "net/http" ) @@ -17,14 +18,40 @@ func NewWorkFlowHandler(database db.Database) *workflowHandler { } } -func (oh *workflowHandler) HandleWorkflowRequest(w http.ResponseWriter, r *http.Request) { - +func (wh *workflowHandler) HandleWorkflowRequest(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { - fmt.Println("Error reading body:", err) - w.WriteHeader(http.StatusBadRequest) + http.Error(w, "Error reading request body", http.StatusBadRequest) + return + } + + var request db.WfRequest + if err := json.Unmarshal(body, &request); err != nil { + http.Error(w, "Invalid request format", http.StatusBadRequest) + return + } + + if request.WorkflowID == "" || request.Source == "" { + http.Error(w, "Missing required fields: workflow_id or source", http.StatusBadRequest) + return + } + + processedRequestID, err := utils.ProcessWorkflowRequest(request.RequestID, request.Source) + if err != nil { + http.Error(w, "Failed to process workflow request", http.StatusInternalServerError) + return + } + + request.Status = db.StatusNew + + if err := wh.db.CreateWorkflowRequest(&request); err != nil { + http.Error(w, "Failed to create workflow request", http.StatusInternalServerError) return } - fmt.Println("Request Body:", string(body)) + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]string{ + "request_id": processedRequestID, + "status": "success", + }) } diff --git a/utils/workflow_processor.go b/utils/workflow_processor.go new file mode 100644 index 000000000..f820f24be --- /dev/null +++ b/utils/workflow_processor.go @@ -0,0 +1,37 @@ +package utils + +import ( + "encoding/json" + "fmt" + "github.com/google/uuid" +) + +type ProcessorConfig struct { + RequiresProcessing bool + HandlerFunc string + Config json.RawMessage +} + +func ProcessWorkflowRequest(requestID string, source string) (string, error) { + + if requestID == "" { + requestID = uuid.New().String() + } + + config := lookupProcessingConfig(source) + + if config == nil { + return requestID, nil + } + + return processWithHandler(requestID) +} + +func lookupProcessingConfig(source string) error { + return nil +} + +func processWithHandler(requestID string) (string, error) { + fmt.Println("Processing with default handler") + return fmt.Sprintf("Processed with default handler, RequestID: %s", requestID), nil +} From fc84556c59124ecdd44340dae7e7339dd2433fab Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Tue, 19 Nov 2024 13:46:59 +0500 Subject: [PATCH 2/6] workflow request unit test --- handlers/workflow_test.go | 70 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 handlers/workflow_test.go diff --git a/handlers/workflow_test.go b/handlers/workflow_test.go new file mode 100644 index 000000000..3fe326ed8 --- /dev/null +++ b/handlers/workflow_test.go @@ -0,0 +1,70 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/google/uuid" + "github.com/stakwork/sphinx-tribes/db" + "github.com/stretchr/testify/assert" +) + +func TestHandleWorkflowRequest(t *testing.T) { + teardownSuite := SetupSuite(t) + defer teardownSuite(t) + + wh := NewWorkFlowHandler(db.TestDB) + + t.Run("successful workflow request", func(t *testing.T) { + request := db.WfRequest{ + WorkflowID: uuid.New().String(), + Source: "test_source", + RequestID: uuid.New().String(), + } + body, _ := json.Marshal(request) + + req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + + wh.HandleWorkflowRequest(w, req) + + assert.Equal(t, http.StatusCreated, w.Code) + var respBody map[string]string + err := json.NewDecoder(w.Body).Decode(&respBody) + assert.NoError(t, err) + assert.Equal(t, "success", respBody["status"]) + assert.NotEmpty(t, respBody["request_id"]) + }) + + t.Run("invalid JSON format", func(t *testing.T) { + req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer([]byte("invalid-json"))) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + + wh.HandleWorkflowRequest(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) + assert.Contains(t, w.Body.String(), "Invalid request format") + }) + + t.Run("missing required fields", func(t *testing.T) { + request := db.WfRequest{ + Source: "test_source", + } + body, _ := json.Marshal(request) + + req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer(body)) + req.Header.Set("Content-Type", "application/json") + w := httptest.NewRecorder() + + wh.HandleWorkflowRequest(w, req) + + assert.Equal(t, http.StatusBadRequest, w.Code) + assert.Contains(t, w.Body.String(), "Missing required fields: workflow_id or source") + }) + +} From 3aeb6854d9adbe83261c2b25f4608e9e7738411d Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Tue, 19 Nov 2024 13:50:19 +0500 Subject: [PATCH 3/6] write workflow request unit test --- handlers/workflow_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/handlers/workflow_test.go b/handlers/workflow_test.go index 3fe326ed8..37909eb89 100644 --- a/handlers/workflow_test.go +++ b/handlers/workflow_test.go @@ -26,7 +26,7 @@ func TestHandleWorkflowRequest(t *testing.T) { } body, _ := json.Marshal(request) - req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer(body)) + req := httptest.NewRequest(http.MethodPost, "/workflows/request", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() @@ -41,7 +41,7 @@ func TestHandleWorkflowRequest(t *testing.T) { }) t.Run("invalid JSON format", func(t *testing.T) { - req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer([]byte("invalid-json"))) + req := httptest.NewRequest(http.MethodPost, "/workflows/request", bytes.NewBuffer([]byte("invalid-json"))) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() @@ -57,7 +57,7 @@ func TestHandleWorkflowRequest(t *testing.T) { } body, _ := json.Marshal(request) - req := httptest.NewRequest(http.MethodPost, "/workflow/request", bytes.NewBuffer(body)) + req := httptest.NewRequest(http.MethodPost, "/workflows/request", bytes.NewBuffer(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() From 0638d6eb21b9fc2e6cf1828158892e27b7aa533e Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Tue, 19 Nov 2024 16:14:36 +0500 Subject: [PATCH 4/6] update handler function and write unit tests --- handlers/workflow.go | 1 + handlers/workflow_test.go | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/handlers/workflow.go b/handlers/workflow.go index 267396933..dff6eb7a9 100644 --- a/handlers/workflow.go +++ b/handlers/workflow.go @@ -43,6 +43,7 @@ func (wh *workflowHandler) HandleWorkflowRequest(w http.ResponseWriter, r *http. } request.Status = db.StatusNew + request.RequestID = processedRequestID if err := wh.db.CreateWorkflowRequest(&request); err != nil { http.Error(w, "Failed to create workflow request", http.StatusInternalServerError) diff --git a/handlers/workflow_test.go b/handlers/workflow_test.go index 37909eb89..089fd174d 100644 --- a/handlers/workflow_test.go +++ b/handlers/workflow_test.go @@ -19,11 +19,18 @@ func TestHandleWorkflowRequest(t *testing.T) { wh := NewWorkFlowHandler(db.TestDB) t.Run("successful workflow request", func(t *testing.T) { + requestData := db.PropertyMap{ + "test_key": "test_value", + } + request := db.WfRequest{ - WorkflowID: uuid.New().String(), - Source: "test_source", - RequestID: uuid.New().String(), + Source: "test_source", + Action: "test_action", + WorkflowID: "workflow_id", + ProjectID: uuid.New().String(), + RequestData: requestData, } + body, _ := json.Marshal(request) req := httptest.NewRequest(http.MethodPost, "/workflows/request", bytes.NewBuffer(body)) From 291424b6e19bae2633376de9eaaa2c6e7b280a14 Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Tue, 19 Nov 2024 20:29:29 +0500 Subject: [PATCH 5/6] correct workflow request handler function and write unit tests --- handlers/workflow.go | 2 +- handlers/workflow_test.go | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/handlers/workflow.go b/handlers/workflow.go index dff6eb7a9..476b9ec2a 100644 --- a/handlers/workflow.go +++ b/handlers/workflow.go @@ -42,8 +42,8 @@ func (wh *workflowHandler) HandleWorkflowRequest(w http.ResponseWriter, r *http. return } - request.Status = db.StatusNew request.RequestID = processedRequestID + request.Status = db.StatusNew if err := wh.db.CreateWorkflowRequest(&request); err != nil { http.Error(w, "Failed to create workflow request", http.StatusInternalServerError) diff --git a/handlers/workflow_test.go b/handlers/workflow_test.go index 089fd174d..16440a027 100644 --- a/handlers/workflow_test.go +++ b/handlers/workflow_test.go @@ -3,13 +3,11 @@ package handlers import ( "bytes" "encoding/json" + "github.com/stakwork/sphinx-tribes/db" + "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" - - "github.com/google/uuid" - "github.com/stakwork/sphinx-tribes/db" - "github.com/stretchr/testify/assert" ) func TestHandleWorkflowRequest(t *testing.T) { @@ -23,11 +21,10 @@ func TestHandleWorkflowRequest(t *testing.T) { "test_key": "test_value", } - request := db.WfRequest{ - Source: "test_source", - Action: "test_action", - WorkflowID: "workflow_id", - ProjectID: uuid.New().String(), + request := &db.WfRequest{ + Source: "test_source_1", + Action: "test_action_1", + WorkflowID: "test_workflow", RequestData: requestData, } @@ -40,6 +37,7 @@ func TestHandleWorkflowRequest(t *testing.T) { wh.HandleWorkflowRequest(w, req) assert.Equal(t, http.StatusCreated, w.Code) + var respBody map[string]string err := json.NewDecoder(w.Body).Decode(&respBody) assert.NoError(t, err) From 3ca181662ad8f9d00f7a395d4914c501e3d79e9d Mon Sep 17 00:00:00 2001 From: MahtabBukhari Date: Tue, 19 Nov 2024 21:21:33 +0500 Subject: [PATCH 6/6] pushed commit --- db/test_config.go | 2 ++ handlers/workflow_test.go | 10 +++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/db/test_config.go b/db/test_config.go index 4416b8b55..6f108576b 100644 --- a/db/test_config.go +++ b/db/test_config.go @@ -58,6 +58,8 @@ func InitTestDB() { db.AutoMigrate(&WorkspaceUsers{}) db.AutoMigrate(&WorkspaceUserRoles{}) db.AutoMigrate(&Bot{}) + db.AutoMigrate(&WfRequest{}) + db.AutoMigrate(&WfProcessingMap{}) people := TestDB.GetAllPeople() for _, p := range people { diff --git a/handlers/workflow_test.go b/handlers/workflow_test.go index 16440a027..66c5b6dc7 100644 --- a/handlers/workflow_test.go +++ b/handlers/workflow_test.go @@ -17,15 +17,11 @@ func TestHandleWorkflowRequest(t *testing.T) { wh := NewWorkFlowHandler(db.TestDB) t.Run("successful workflow request", func(t *testing.T) { - requestData := db.PropertyMap{ - "test_key": "test_value", - } request := &db.WfRequest{ - Source: "test_source_1", - Action: "test_action_1", - WorkflowID: "test_workflow", - RequestData: requestData, + Source: "test_source_1", + Action: "test_action_1", + WorkflowID: "test_workflow", } body, _ := json.Marshal(request)