This is an automated email from the ASF dual-hosted git repository.
warren 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 d4a195761 fix(q_dev): fix task logging (#8503)
d4a195761 is described below
commit d4a19576182b61b3db17460058f3ccba946e991a
Author: DiscreteTom <[email protected]>
AuthorDate: Mon Aug 4 20:23:16 2025 +0800
fix(q_dev): fix task logging (#8503)
---
backend/plugins/q_dev/api/connection_test.go | 4 +-
backend/plugins/q_dev/impl/impl.go | 1 +
.../migrationscripts/archived/user_metrics.go | 3 +-
backend/plugins/q_dev/models/user_data_test.go | 98 +++++------
backend/plugins/q_dev/tasks/s3_data_extractor.go | 21 ++-
.../plugins/q_dev/tasks/s3_data_extractor_test.go | 188 ++++++++++++++-------
6 files changed, 190 insertions(+), 125 deletions(-)
diff --git a/backend/plugins/q_dev/api/connection_test.go
b/backend/plugins/q_dev/api/connection_test.go
index 916fbd155..6c39dee3f 100644
--- a/backend/plugins/q_dev/api/connection_test.go
+++ b/backend/plugins/q_dev/api/connection_test.go
@@ -231,11 +231,11 @@ func TestConnectionSanitization_PreservesIdentityStore(t
*testing.T) {
// Secret should be sanitized
assert.NotEqual(t, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
sanitized.SecretAccessKey)
-
+
// Identity Store fields should be preserved
assert.Equal(t, "d-1234567890", sanitized.IdentityStoreId)
assert.Equal(t, "us-west-2", sanitized.IdentityStoreRegion)
-
+
// Other fields should be preserved
assert.Equal(t, "AKIAIOSFODNN7EXAMPLE", sanitized.AccessKeyId)
assert.Equal(t, "us-east-1", sanitized.Region)
diff --git a/backend/plugins/q_dev/impl/impl.go
b/backend/plugins/q_dev/impl/impl.go
index 5cf8bf393..b2568334b 100644
--- a/backend/plugins/q_dev/impl/impl.go
+++ b/backend/plugins/q_dev/impl/impl.go
@@ -19,6 +19,7 @@ package impl
import (
"fmt"
+
"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
diff --git
a/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
b/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
index d26b75aea..be948feea 100644
--- a/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
+++ b/backend/plugins/q_dev/models/migrationscripts/archived/user_metrics.go
@@ -18,8 +18,9 @@ limitations under the License.
package archived
import (
-
"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
"time"
+
+
"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
)
// QDevUserMetrics 存储按用户聚合的指标数据
diff --git a/backend/plugins/q_dev/models/user_data_test.go
b/backend/plugins/q_dev/models/user_data_test.go
index d45d1748f..74d5dfcfe 100644
--- a/backend/plugins/q_dev/models/user_data_test.go
+++ b/backend/plugins/q_dev/models/user_data_test.go
@@ -20,7 +20,7 @@ package models
import (
"testing"
"time"
-
+
"github.com/stretchr/testify/assert"
)
@@ -28,59 +28,59 @@ func TestQDevUserDataAllMetrics(t *testing.T) {
// Create a test user data object with all metrics
userData := &QDevUserData{
ConnectionId: 1,
- UserId: "test-user-id",
- Date: time.Now(),
- DisplayName: "Test User",
-
+ UserId: "test-user-id",
+ Date: time.Now(),
+ DisplayName: "Test User",
+
// Set values for existing metrics
- CodeReview_FindingsCount: 10,
- CodeReview_SucceededEventCount: 11,
- InlineChat_AcceptanceEventCount: 12,
- InlineChat_AcceptedLineAdditions: 13,
- InlineChat_AcceptedLineDeletions: 14,
- InlineChat_DismissalEventCount: 15,
+ CodeReview_FindingsCount: 10,
+ CodeReview_SucceededEventCount: 11,
+ InlineChat_AcceptanceEventCount: 12,
+ InlineChat_AcceptedLineAdditions: 13,
+ InlineChat_AcceptedLineDeletions: 14,
+ InlineChat_DismissalEventCount: 15,
InlineChat_DismissedLineAdditions: 16,
InlineChat_DismissedLineDeletions: 17,
- InlineChat_RejectedLineAdditions: 18,
- InlineChat_RejectedLineDeletions: 19,
- InlineChat_RejectionEventCount: 20,
- InlineChat_TotalEventCount: 21,
- Inline_AICodeLines: 22,
- Inline_AcceptanceCount: 23,
- Inline_SuggestionsCount: 24,
-
+ InlineChat_RejectedLineAdditions: 18,
+ InlineChat_RejectedLineDeletions: 19,
+ InlineChat_RejectionEventCount: 20,
+ InlineChat_TotalEventCount: 21,
+ Inline_AICodeLines: 22,
+ Inline_AcceptanceCount: 23,
+ Inline_SuggestionsCount: 24,
+
// Set values for new metrics
- Chat_AICodeLines: 25,
- Chat_MessagesInteracted: 26,
- Chat_MessagesSent: 27,
- CodeFix_AcceptanceEventCount: 28,
- CodeFix_AcceptedLines: 29,
- CodeFix_GeneratedLines: 30,
- CodeFix_GenerationEventCount: 31,
- CodeReview_FailedEventCount: 32,
- Dev_AcceptanceEventCount: 33,
- Dev_AcceptedLines: 34,
- Dev_GeneratedLines: 35,
- Dev_GenerationEventCount: 36,
- DocGeneration_AcceptedFileUpdates: 37,
+ Chat_AICodeLines: 25,
+ Chat_MessagesInteracted: 26,
+ Chat_MessagesSent: 27,
+ CodeFix_AcceptanceEventCount: 28,
+ CodeFix_AcceptedLines: 29,
+ CodeFix_GeneratedLines: 30,
+ CodeFix_GenerationEventCount: 31,
+ CodeReview_FailedEventCount: 32,
+ Dev_AcceptanceEventCount: 33,
+ Dev_AcceptedLines: 34,
+ Dev_GeneratedLines: 35,
+ Dev_GenerationEventCount: 36,
+ DocGeneration_AcceptedFileUpdates: 37,
DocGeneration_AcceptedFilesCreations: 38,
- DocGeneration_AcceptedLineAdditions: 39,
- DocGeneration_AcceptedLineUpdates: 40,
- DocGeneration_EventCount: 41,
- DocGeneration_RejectedFileCreations: 42,
- DocGeneration_RejectedFileUpdates: 43,
- DocGeneration_RejectedLineAdditions: 44,
- DocGeneration_RejectedLineUpdates: 45,
- TestGeneration_AcceptedLines: 46,
- TestGeneration_AcceptedTests: 47,
- TestGeneration_EventCount: 48,
- TestGeneration_GeneratedLines: 49,
- TestGeneration_GeneratedTests: 50,
- Transformation_EventCount: 51,
- Transformation_LinesGenerated: 52,
- Transformation_LinesIngested: 53,
+ DocGeneration_AcceptedLineAdditions: 39,
+ DocGeneration_AcceptedLineUpdates: 40,
+ DocGeneration_EventCount: 41,
+ DocGeneration_RejectedFileCreations: 42,
+ DocGeneration_RejectedFileUpdates: 43,
+ DocGeneration_RejectedLineAdditions: 44,
+ DocGeneration_RejectedLineUpdates: 45,
+ TestGeneration_AcceptedLines: 46,
+ TestGeneration_AcceptedTests: 47,
+ TestGeneration_EventCount: 48,
+ TestGeneration_GeneratedLines: 49,
+ TestGeneration_GeneratedTests: 50,
+ Transformation_EventCount: 51,
+ Transformation_LinesGenerated: 52,
+ Transformation_LinesIngested: 53,
}
-
+
// Verify that all metrics are accessible
// Existing metrics
assert.Equal(t, 10, userData.CodeReview_FindingsCount)
@@ -98,7 +98,7 @@ func TestQDevUserDataAllMetrics(t *testing.T) {
assert.Equal(t, 22, userData.Inline_AICodeLines)
assert.Equal(t, 23, userData.Inline_AcceptanceCount)
assert.Equal(t, 24, userData.Inline_SuggestionsCount)
-
+
// New metrics
assert.Equal(t, 25, userData.Chat_AICodeLines)
assert.Equal(t, 26, userData.Chat_MessagesInteracted)
diff --git a/backend/plugins/q_dev/tasks/s3_data_extractor.go
b/backend/plugins/q_dev/tasks/s3_data_extractor.go
index f091e15b9..10ab6a7cd 100644
--- a/backend/plugins/q_dev/tasks/s3_data_extractor.go
+++ b/backend/plugins/q_dev/tasks/s3_data_extractor.go
@@ -119,7 +119,7 @@ func processCSVData(taskCtx plugin.SubTaskContext, db
dal.Dal, reader io.ReadClo
// 读取标头
headers, err := csvReader.Read()
- fmt.Printf("headers: %+v\n", headers)
+ taskCtx.GetLogger().Debug("CSV headers: %+v", headers)
if err != nil {
return errors.Convert(err)
}
@@ -135,7 +135,7 @@ func processCSVData(taskCtx plugin.SubTaskContext, db
dal.Dal, reader io.ReadClo
}
// 创建用户数据对象 (updated to include display name resolution)
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, data.IdentityClient)
+ userData, err :=
createUserDataWithDisplayName(taskCtx.GetLogger(), headers, record, fileMeta,
data.IdentityClient)
if err != nil {
return errors.Default.Wrap(err, "failed to create user
data")
}
@@ -156,7 +156,9 @@ type UserDisplayNameResolver interface {
}
// 从CSV记录创建用户数据对象 (enhanced with display name resolution)
-func createUserDataWithDisplayName(headers []string, record []string, fileMeta
*models.QDevS3FileMeta, identityClient UserDisplayNameResolver)
(*models.QDevUserData, errors.Error) {
+func createUserDataWithDisplayName(logger interface {
+ Debug(format string, a ...interface{})
+}, headers []string, record []string, fileMeta *models.QDevS3FileMeta,
identityClient UserDisplayNameResolver) (*models.QDevUserData, errors.Error) {
userData := &models.QDevUserData{
ConnectionId: fileMeta.ConnectionId,
}
@@ -165,13 +167,12 @@ func createUserDataWithDisplayName(headers []string,
record []string, fileMeta *
fieldMap := make(map[string]string)
for i, header := range headers {
if i < len(record) {
- // 打印每个header和对应的值,帮助调试
- fmt.Printf("Mapping header[%d]: '%s' -> '%s'\n", i,
header, record[i])
+ logger.Debug("Mapping header[%d]: '%s' -> '%s'", i,
header, record[i])
fieldMap[header] = record[i]
// 同时添加去除空格的版本
trimmedHeader := strings.TrimSpace(header)
if trimmedHeader != header {
- fmt.Printf("Also adding trimmed header:
'%s'\n", trimmedHeader)
+ logger.Debug("Also adding trimmed header:
'%s'", trimmedHeader)
fieldMap[trimmedHeader] = record[i]
}
}
@@ -188,7 +189,7 @@ func createUserDataWithDisplayName(headers []string, record
[]string, fileMeta *
}
// 设置DisplayName (new functionality)
- userData.DisplayName = resolveDisplayName(userData.UserId,
identityClient)
+ userData.DisplayName = resolveDisplayName(logger, userData.UserId,
identityClient)
// 设置Date
dateStr, ok := fieldMap["Date"]
@@ -251,7 +252,9 @@ func createUserDataWithDisplayName(headers []string, record
[]string, fileMeta *
}
// resolveDisplayName resolves user ID to display name using Identity Client
-func resolveDisplayName(userId string, identityClient UserDisplayNameResolver)
string {
+func resolveDisplayName(logger interface {
+ Debug(format string, a ...interface{})
+}, userId string, identityClient UserDisplayNameResolver) string {
// If no identity client available, use userId as fallback
if identityClient == nil {
return userId
@@ -261,7 +264,7 @@ func resolveDisplayName(userId string, identityClient
UserDisplayNameResolver) s
displayName, err := identityClient.ResolveUserDisplayName(userId)
if err != nil {
// Log error but continue with userId as fallback
- fmt.Printf("Failed to resolve display name for user %s: %v\n",
userId, err)
+ logger.Debug("Failed to resolve display name for user %s: %v",
userId, err)
return userId
}
diff --git a/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
b/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
index 1e84e81ef..fbea299dc 100644
--- a/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
+++ b/backend/plugins/q_dev/tasks/s3_data_extractor_test.go
@@ -40,18 +40,32 @@ func (m *MockIdentityClient) ResolveUserDisplayName(userId
string) (string, erro
// Ensure MockIdentityClient implements UserDisplayNameResolver
var _ UserDisplayNameResolver = (*MockIdentityClient)(nil)
+// MockLogger is a mock implementation of the logger interface for testing
+type MockLogger struct {
+ mock.Mock
+}
+
+func (m *MockLogger) Debug(format string, args ...interface{}) {
+ m.Called(format, args)
+}
+
func TestCreateUserDataWithDisplayName_Success(t *testing.T) {
headers := []string{"UserId", "Date", "CodeReview_FindingsCount",
"Inline_AcceptanceCount"}
record := []string{"user-123", "2025-06-23", "5", "10"}
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"user-123").Return("John Doe", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
assert.Equal(t, "user-123", userData.UserId)
@@ -59,7 +73,7 @@ func TestCreateUserDataWithDisplayName_Success(t *testing.T) {
assert.Equal(t, uint64(1), userData.ConnectionId)
assert.Equal(t, 5, userData.CodeReview_FindingsCount)
assert.Equal(t, 10, userData.Inline_AcceptanceCount)
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -69,17 +83,23 @@ func TestCreateUserDataWithDisplayName_FallbackToUUID(t
*testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"user-456").Return("user-456", assert.AnError)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Failed to resolve display name for user %s:
%v", mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
assert.Equal(t, "user-456", userData.UserId)
assert.Equal(t, "user-456", userData.DisplayName) // Should fallback to
UUID
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -89,9 +109,14 @@ func TestCreateUserDataWithDisplayName_NoIdentityClient(t
*testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, nil)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, nil)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
assert.Equal(t, "user-789", userData.UserId)
@@ -104,17 +129,22 @@ func TestCreateUserDataWithDisplayName_EmptyDisplayName(t
*testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"user-empty").Return("", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
assert.Equal(t, "user-empty", userData.UserId)
assert.Equal(t, "user-empty", userData.DisplayName) // Should fallback
when empty
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -134,24 +164,29 @@ func
TestCreateUserDataWithDisplayName_AllExistingMetrics(t *testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 123,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"test-user").Return("Test User", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
-
+
// Verify basic fields
assert.Equal(t, "test-user", userData.UserId)
assert.Equal(t, "Test User", userData.DisplayName)
assert.Equal(t, uint64(123), userData.ConnectionId)
-
+
// Verify date parsing
expectedDate, _ := time.Parse("2006-01-02", "2025-06-23")
assert.Equal(t, expectedDate, userData.Date)
-
+
// Verify all existing metric fields
assert.Equal(t, 1, userData.CodeReview_FindingsCount)
assert.Equal(t, 2, userData.CodeReview_SucceededEventCount)
@@ -168,7 +203,7 @@ func TestCreateUserDataWithDisplayName_AllExistingMetrics(t
*testing.T) {
assert.Equal(t, 13, userData.Inline_AICodeLines)
assert.Equal(t, 14, userData.Inline_AcceptanceCount)
assert.Equal(t, 15, userData.Inline_SuggestionsCount)
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -186,30 +221,35 @@ func TestCreateUserDataWithDisplayName_AllNewMetrics(t
*testing.T) {
"TestGeneration_GeneratedLines",
"TestGeneration_GeneratedTests",
"Transformation_EventCount", "Transformation_LinesGenerated",
"Transformation_LinesIngested",
}
-
+
record := []string{
"test-user", "2025-06-23",
"101", "102", "103", "104", "105", "106", "107", "108", "109",
"110",
"111", "112", "113", "114", "115", "116", "117", "118", "119",
"120",
"121", "122", "123", "124", "125", "126", "127", "128", "129",
}
-
+
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 123,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"test-user").Return("Test User", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
-
+
// Verify basic fields
assert.Equal(t, "test-user", userData.UserId)
assert.Equal(t, "Test User", userData.DisplayName)
-
+
// Verify all new metric fields
assert.Equal(t, 101, userData.Chat_AICodeLines)
assert.Equal(t, 102, userData.Chat_MessagesInteracted)
@@ -240,7 +280,7 @@ func TestCreateUserDataWithDisplayName_AllNewMetrics(t
*testing.T) {
assert.Equal(t, 127, userData.Transformation_EventCount)
assert.Equal(t, 128, userData.Transformation_LinesGenerated)
assert.Equal(t, 129, userData.Transformation_LinesIngested)
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -248,60 +288,70 @@ func TestCreateUserDataWithDisplayName_MissingMetrics(t
*testing.T) {
// Only provide a few metrics in the CSV
headers := []string{"UserId", "Date", "CodeReview_FindingsCount",
"Chat_AICodeLines"}
record := []string{"test-user", "2025-06-23", "42", "99"}
-
+
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 123,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"test-user").Return("Test User", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
-
+
// Verify provided metrics are set correctly
assert.Equal(t, 42, userData.CodeReview_FindingsCount)
assert.Equal(t, 99, userData.Chat_AICodeLines)
-
+
// Verify missing metrics are set to 0
assert.Equal(t, 0, userData.CodeReview_SucceededEventCount)
assert.Equal(t, 0, userData.InlineChat_AcceptanceEventCount)
assert.Equal(t, 0, userData.Chat_MessagesInteracted)
assert.Equal(t, 0, userData.TestGeneration_AcceptedTests)
assert.Equal(t, 0, userData.Transformation_LinesIngested)
-
+
mockIdentityClient.AssertExpectations(t)
}
func TestCreateUserDataWithDisplayName_InvalidMetricValues(t *testing.T) {
headers := []string{
- "UserId", "Date", "CodeReview_FindingsCount",
"Chat_AICodeLines",
+ "UserId", "Date", "CodeReview_FindingsCount",
"Chat_AICodeLines",
"InlineChat_AcceptanceEventCount",
"TestGeneration_AcceptedTests",
}
record := []string{"test-user", "2025-06-23", "42", "not-a-number",
"abc", ""}
-
+
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 123,
}
-
+
mockIdentityClient := &MockIdentityClient{}
mockIdentityClient.On("ResolveUserDisplayName",
"test-user").Return("Test User", nil)
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, mockIdentityClient)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, mockIdentityClient)
+
assert.NoError(t, err)
assert.NotNil(t, userData)
-
+
// Verify valid metric is set correctly
assert.Equal(t, 42, userData.CodeReview_FindingsCount)
-
+
// Verify invalid metrics are set to 0
assert.Equal(t, 0, userData.Chat_AICodeLines)
assert.Equal(t, 0, userData.InlineChat_AcceptanceEventCount)
assert.Equal(t, 0, userData.TestGeneration_AcceptedTests)
-
+
mockIdentityClient.AssertExpectations(t)
}
@@ -311,9 +361,14 @@ func TestCreateUserDataWithDisplayName_MissingUserId(t
*testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, nil)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, nil)
+
assert.Error(t, err)
assert.Nil(t, userData)
assert.Contains(t, err.Error(), "UserId not found")
@@ -325,9 +380,14 @@ func TestCreateUserDataWithDisplayName_MissingDate(t
*testing.T) {
fileMeta := &models.QDevS3FileMeta{
ConnectionId: 1,
}
-
- userData, err := createUserDataWithDisplayName(headers, record,
fileMeta, nil)
-
+
+ mockLogger := &MockLogger{}
+ // Add expectations for Debug calls
+ mockLogger.On("Debug", "Mapping header[%d]: '%s' -> '%s'",
mock.Anything).Return()
+ mockLogger.On("Debug", "Also adding trimmed header: '%s'",
mock.Anything).Return()
+
+ userData, err := createUserDataWithDisplayName(mockLogger, headers,
record, fileMeta, nil)
+
assert.Error(t, err)
assert.Nil(t, userData)
assert.Contains(t, err.Error(), "Date not found")
@@ -346,10 +406,10 @@ func TestParseDate(t *testing.T) {
{"2025-07-10T15:04:05Z", time.Date(2025, 7, 10, 15, 4, 5, 0,
time.UTC), false},
{"invalid-date", time.Time{}, true},
}
-
+
for _, tc := range testCases {
date, err := parseDate(tc.dateStr)
-
+
if tc.expectError {
assert.Error(t, err)
} else {
@@ -361,13 +421,13 @@ func TestParseDate(t *testing.T) {
func TestParseInt(t *testing.T) {
fieldMap := map[string]string{
- "ValidInt": "42",
- "ZeroInt": "0",
+ "ValidInt": "42",
+ "ZeroInt": "0",
"NegativeInt": "-10",
- "InvalidInt": "not-a-number",
+ "InvalidInt": "not-a-number",
"EmptyString": "",
}
-
+
assert.Equal(t, 42, parseInt(fieldMap, "ValidInt"))
assert.Equal(t, 0, parseInt(fieldMap, "ZeroInt"))
assert.Equal(t, -10, parseInt(fieldMap, "NegativeInt"))