This is an automated email from the ASF dual-hosted git repository.

zky pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 5b98ee1e7 feat(qa): add is_invalid field to qa_test_case_executions 
(#8764)
5b98ee1e7 is described below

commit 5b98ee1e74cd9ca89035ba47bc6fe0d66c2c1ed4
Author: NaRro <[email protected]>
AuthorDate: Tue Mar 17 02:19:11 2026 +0000

    feat(qa): add is_invalid field to qa_test_case_executions (#8764)
    
    * feat(qa): add is_invalid field to qa_test_case_executions
    
    Add is_invalid boolean field to the domain layer qa_test_case_executions
    table to allow QA teams to flag test executions as invalid due to
    environmental issues, flaky tests, false positives, or false negatives.
    
    Changes:
    - Add IsInvalid field to QaTestCaseExecution domain model
    - Create migration script 
(20260313_add_is_invalid_to_qa_test_case_executions)
    - Register migration in migrationscripts/register.go
    - Update customize service to set default value for is_invalid
    - Update E2E test data to include new column
    
    Resolves #8763
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    
    * fix(qa): handle missing is_invalid column in CSV import
    
    Fix PostgreSQL compatibility issue when CSV files don't contain
    the is_invalid column. The field now defaults to false instead
    of an empty string.
    
    Changes:
    - Update qaTestCaseExecutionHandler to check for empty string values
    - Add E2E test for backward compatibility with CSV files lacking is_invalid
    - Add explicit IsInvalid initialization in Testmo plugin converter
    
    Resolves #8763
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .../domainlayer/qa/qa_test_case_execution.go       |  1 +
 ...13_add_is_invalid_to_qa_test_case_executions.go | 52 ++++++++++++++++++++++
 backend/core/models/migrationscripts/register.go   |  1 +
 .../e2e/import_test_case_execution_test.go         | 50 +++++++++++++++++++++
 .../qa_test_case_executions_output.csv             |  8 ++--
 .../qa_test_case_executions_output_incremental.csv | 10 ++---
 ...case_executions_output_no_is_invalid_column.csv |  4 ++
 backend/plugins/customize/service/service.go       |  4 ++
 8 files changed, 121 insertions(+), 9 deletions(-)

diff --git a/backend/core/models/domainlayer/qa/qa_test_case_execution.go 
b/backend/core/models/domainlayer/qa/qa_test_case_execution.go
index cfab89b6d..aaf237b6f 100644
--- a/backend/core/models/domainlayer/qa/qa_test_case_execution.go
+++ b/backend/core/models/domainlayer/qa/qa_test_case_execution.go
@@ -33,6 +33,7 @@ type QaTestCaseExecution struct {
        FinishTime   time.Time `gorm:"comment:Test finish time"`
        CreatorId    string    `gorm:"type:varchar(255);comment:Executor ID"`
        Status       string    `gorm:"type:varchar(255);comment:Test execution 
status | PENDING | IN_PROGRESS | SUCCESS | FAILED"` // enum, using string
+       IsInvalid    bool
 }
 
 func (QaTestCaseExecution) TableName() string {
diff --git 
a/backend/core/models/migrationscripts/20260313_add_is_invalid_to_qa_test_case_executions.go
 
b/backend/core/models/migrationscripts/20260313_add_is_invalid_to_qa_test_case_executions.go
new file mode 100644
index 000000000..ce7656e1e
--- /dev/null
+++ 
b/backend/core/models/migrationscripts/20260313_add_is_invalid_to_qa_test_case_executions.go
@@ -0,0 +1,52 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+       "github.com/apache/incubator-devlake/core/context"
+       "github.com/apache/incubator-devlake/core/errors"
+       "github.com/apache/incubator-devlake/core/plugin"
+)
+
+var _ plugin.MigrationScript = (*addIsInvalidToQaTestCaseExecution)(nil)
+
+type qaTestCaseExecution20260313 struct {
+       IsInvalid bool
+}
+
+func (qaTestCaseExecution20260313) TableName() string {
+       return "qa_test_case_executions"
+}
+
+type addIsInvalidToQaTestCaseExecution struct{}
+
+func (*addIsInvalidToQaTestCaseExecution) Up(basicRes context.BasicRes) 
errors.Error {
+       db := basicRes.GetDal()
+       if err := db.AutoMigrate(&qaTestCaseExecution20260313{}); err != nil {
+               return err
+       }
+       return nil
+}
+
+func (*addIsInvalidToQaTestCaseExecution) Version() uint64 {
+       return 20260313100000
+}
+
+func (*addIsInvalidToQaTestCaseExecution) Name() string {
+       return "add is_invalid to qa_test_case_executions"
+}
diff --git a/backend/core/models/migrationscripts/register.go 
b/backend/core/models/migrationscripts/register.go
index 5b682b662..9372d8fbd 100644
--- a/backend/core/models/migrationscripts/register.go
+++ b/backend/core/models/migrationscripts/register.go
@@ -136,6 +136,7 @@ func All() []plugin.MigrationScript {
                new(addCqIssueImpacts),
                new(addDueDateToIssues),
                new(createQaTables),
+               new(addIsInvalidToQaTestCaseExecution),
                new(increaseCqIssueComponentLength),
                new(extendFieldSizeForCq),
                new(addIssueFixVerion),
diff --git a/backend/plugins/customize/e2e/import_test_case_execution_test.go 
b/backend/plugins/customize/e2e/import_test_case_execution_test.go
index 92d5750b8..a74c69940 100644
--- a/backend/plugins/customize/e2e/import_test_case_execution_test.go
+++ b/backend/plugins/customize/e2e/import_test_case_execution_test.go
@@ -71,6 +71,7 @@ func TestImportQaTestCaseExecutionsDataFlow(t *testing.T) {
                        "start_time",
                        "finish_time",
                        "creator_id",
+                       "is_invalid",
                        "status",
                })
        dataflowTester.VerifyTableWithRawData(
@@ -104,6 +105,7 @@ func TestImportQaTestCaseExecutionsDataFlow(t *testing.T) {
                        "start_time",
                        "finish_time",
                        "creator_id",
+                       "is_invalid",
                        "status",
                })
 
@@ -117,3 +119,51 @@ func TestImportQaTestCaseExecutionsDataFlow(t *testing.T) {
                },
        )
 }
+
+// TestImportQaTestCaseExecutions_NoIsInvalidColumn tests backward 
compatibility:
+// Verifies that importing CSV files without the is_invalid column works 
correctly,
+// and the is_invalid field defaults to false.
+func TestImportQaTestCaseExecutions_NoIsInvalidColumn(t *testing.T) {
+       var plugin impl.Customize
+       dataflowTester := e2ehelper.NewDataFlowTester(t, "customize", plugin)
+
+       // Flush the relevant table
+       dataflowTester.FlushTabler(&qa.QaTestCaseExecution{})
+       dataflowTester.FlushTabler(&crossdomain.Account{})
+
+       // Create a new service instance
+       svc := service.NewService(dataflowTester.Dal)
+
+       // Use the existing CSV file that does NOT contain is_invalid column
+       // This simulates backward compatibility with old CSV files
+       qaTestCaseExecutionsFile, err := 
os.Open("raw_tables/qa_test_case_executions_input.csv")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer qaTestCaseExecutionsFile.Close()
+
+       // Define a dummy qaProjectId
+       qaProjectId := "test-backward-compat-project"
+
+       // Import data from the CSV file (which has no is_invalid column)
+       err = svc.ImportQaTestCaseExecutions(qaProjectId, 
qaTestCaseExecutionsFile, false)
+       if err != nil {
+               t.Fatalf("ImportQaTestCaseExecutions failed: %v", err)
+       }
+
+       // Verify the imported data has is_invalid defaulted to false
+       dataflowTester.VerifyTableWithRawData(
+               &qa.QaTestCaseExecution{},
+               
"snapshot_tables/qa_test_case_executions_output_no_is_invalid_column.csv",
+               []string{
+                       "id",
+                       "qa_project_id",
+                       "qa_test_case_id",
+                       "create_time",
+                       "start_time",
+                       "finish_time",
+                       "creator_id",
+                       "is_invalid",
+                       "status",
+               })
+}
diff --git 
a/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output.csv
 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output.csv
index 1d51d4a0d..cd78e9ec5 100644
--- 
a/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output.csv
+++ 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output.csv
@@ -1,4 +1,4 @@
-id,qa_project_id,qa_test_case_id,create_time,start_time,finish_time,creator_id,status,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
-exec-1,test-qa-project-id,tc-1,2023-03-01T10:00:00.000+00:00,2023-03-01T10:01:00.000+00:00,2023-03-01T10:05:00.000+00:00,csv:CsvAccount:0:user-a,SUCCESS,test-qa-project-id,,,
-exec-2,test-qa-project-id,tc-2,2023-03-01T11:00:00.000+00:00,2023-03-01T11:02:00.000+00:00,2023-03-01T11:06:00.000+00:00,csv:CsvAccount:0:user-b,FAILED,test-qa-project-id,,,
-exec-3,test-qa-project-id,tc-1,2023-03-02T10:00:00.000+00:00,2023-03-02T10:01:00.000+00:00,2023-03-02T10:04:00.000+00:00,csv:CsvAccount:0:user-a,SUCCESS,test-qa-project-id,,,
+id,qa_project_id,qa_test_case_id,create_time,start_time,finish_time,creator_id,is_invalid,status,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+exec-1,test-qa-project-id,tc-1,2023-03-01T10:00:00.000+00:00,2023-03-01T10:01:00.000+00:00,2023-03-01T10:05:00.000+00:00,csv:CsvAccount:0:user-a,0,SUCCESS,test-qa-project-id,,,
+exec-2,test-qa-project-id,tc-2,2023-03-01T11:00:00.000+00:00,2023-03-01T11:02:00.000+00:00,2023-03-01T11:06:00.000+00:00,csv:CsvAccount:0:user-b,0,FAILED,test-qa-project-id,,,
+exec-3,test-qa-project-id,tc-1,2023-03-02T10:00:00.000+00:00,2023-03-02T10:01:00.000+00:00,2023-03-02T10:04:00.000+00:00,csv:CsvAccount:0:user-a,0,SUCCESS,test-qa-project-id,,,
diff --git 
a/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_incremental.csv
 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_incremental.csv
index e214d734b..90e496a27 100644
--- 
a/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_incremental.csv
+++ 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_incremental.csv
@@ -1,5 +1,5 @@
-id,qa_project_id,qa_test_case_id,create_time,start_time,finish_time,creator_id,status,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
-exec-1,test-qa-project-id,tc-1,2023-03-04T10:00:00.000+00:00,2023-03-04T10:01:00.000+00:00,2023-03-04T10:06:00.000+00:00,csv:CsvAccount:0:user-a,FAILED,test-qa-project-id,,,
-exec-2,test-qa-project-id,tc-2,2023-03-01T11:00:00.000+00:00,2023-03-01T11:02:00.000+00:00,2023-03-01T11:06:00.000+00:00,csv:CsvAccount:0:user-b,FAILED,test-qa-project-id,,,
-exec-3,test-qa-project-id,tc-1,2023-03-02T10:00:00.000+00:00,2023-03-02T10:01:00.000+00:00,2023-03-02T10:04:00.000+00:00,csv:CsvAccount:0:user-a,SUCCESS,test-qa-project-id,,,
-exec-4,test-qa-project-id,tc-3,2023-03-03T10:00:00.000+00:00,2023-03-03T10:01:00.000+00:00,2023-03-03T10:05:00.000+00:00,csv:CsvAccount:0:user-c,SUCCESS,test-qa-project-id,,,
+id,qa_project_id,qa_test_case_id,create_time,start_time,finish_time,creator_id,is_invalid,status,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+exec-1,test-qa-project-id,tc-1,2023-03-04T10:00:00.000+00:00,2023-03-04T10:01:00.000+00:00,2023-03-04T10:06:00.000+00:00,csv:CsvAccount:0:user-a,0,FAILED,test-qa-project-id,,,
+exec-2,test-qa-project-id,tc-2,2023-03-01T11:00:00.000+00:00,2023-03-01T11:02:00.000+00:00,2023-03-01T11:06:00.000+00:00,csv:CsvAccount:0:user-b,0,FAILED,test-qa-project-id,,,
+exec-3,test-qa-project-id,tc-1,2023-03-02T10:00:00.000+00:00,2023-03-02T10:01:00.000+00:00,2023-03-02T10:04:00.000+00:00,csv:CsvAccount:0:user-a,0,SUCCESS,test-qa-project-id,,,
+exec-4,test-qa-project-id,tc-3,2023-03-03T10:00:00.000+00:00,2023-03-03T10:01:00.000+00:00,2023-03-03T10:05:00.000+00:00,csv:CsvAccount:0:user-c,0,SUCCESS,test-qa-project-id,,,
diff --git 
a/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_no_is_invalid_column.csv
 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_no_is_invalid_column.csv
new file mode 100644
index 000000000..e313377a0
--- /dev/null
+++ 
b/backend/plugins/customize/e2e/snapshot_tables/qa_test_case_executions_output_no_is_invalid_column.csv
@@ -0,0 +1,4 @@
+id,qa_project_id,qa_test_case_id,create_time,start_time,finish_time,creator_id,is_invalid,status,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
+exec-1,test-backward-compat-project,tc-1,2023-03-01T10:00:00.000+00:00,2023-03-01T10:01:00.000+00:00,2023-03-01T10:05:00.000+00:00,csv:CsvAccount:0:user-a,0,SUCCESS,test-backward-compat-project,,,
+exec-2,test-backward-compat-project,tc-2,2023-03-01T11:00:00.000+00:00,2023-03-01T11:02:00.000+00:00,2023-03-01T11:06:00.000+00:00,csv:CsvAccount:0:user-b,0,FAILED,test-backward-compat-project,,,
+exec-3,test-backward-compat-project,tc-1,2023-03-02T10:00:00.000+00:00,2023-03-02T10:01:00.000+00:00,2023-03-02T10:04:00.000+00:00,csv:CsvAccount:0:user-a,0,SUCCESS,test-backward-compat-project,,,
\ No newline at end of file
diff --git a/backend/plugins/customize/service/service.go 
b/backend/plugins/customize/service/service.go
index 89e8833cf..5ef3bcbb3 100644
--- a/backend/plugins/customize/service/service.go
+++ b/backend/plugins/customize/service/service.go
@@ -541,6 +541,10 @@ func (s *Service) qaTestCaseExecutionHandler(qaProjectId 
string) func(record map
                }
                delete(record, "creator_name")
                record["qa_project_id"] = qaProjectId
+               // Set default value for is_invalid if not present or empty in 
the CSV
+               if isInvalid, exists := record["is_invalid"]; !exists || 
isInvalid == "" {
+                       record["is_invalid"] = false
+               }
                return s.dal.CreateWithMap(&qa.QaTestCaseExecution{}, record)
        }
 }

Reply via email to