From 2f2d4a14977754c51f6faca1153da1103eaf5636 Mon Sep 17 00:00:00 2001 From: Dawid Rusnak Date: Fri, 7 Jun 2024 15:53:58 +0200 Subject: [PATCH] fix(testworkflows): support non-UTC timezone in Kubernetes logs (#5552) --- .../testworkflowcontroller/logs.go | 19 ++++++-- .../testworkflowcontroller/logs_test.go | 43 +++++++++++++++++++ .../testworkflowcontroller/utils.go | 3 +- 3 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 pkg/tcl/testworkflowstcl/testworkflowcontroller/logs_test.go diff --git a/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs.go b/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs.go index e4057901597..e0b65816b24 100644 --- a/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs.go +++ b/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs.go @@ -150,7 +150,7 @@ func WatchContainerLogs(ctx context.Context, clientSet kubernetes.Interface, nam } func ReadTimestamp(reader *bufio.Reader) (time.Time, []byte, error) { - tsPrefix := make([]byte, 31) // 30 bytes for timestamp + 1 byte for space + tsPrefix := make([]byte, 31, 35) // 30 bytes for timestamp + 1 byte for space + 4 additional bytes for non-UTC timezone count, err := io.ReadFull(reader, tsPrefix) if err != nil { return time.Time{}, nil, err @@ -158,9 +158,22 @@ func ReadTimestamp(reader *bufio.Reader) (time.Time, []byte, error) { if count < 31 { return time.Time{}, nil, io.EOF } - ts, err := time.Parse(KubernetesLogTimeFormat, string(tsPrefix[0:30])) + var ts time.Time + // Handle non-UTC timezones + if tsPrefix[29] == '+' { + tsSuffix := make([]byte, 5) + count, err = io.ReadFull(reader, tsSuffix) + if err != nil { + return time.Time{}, nil, err + } + if count < 5 { + return time.Time{}, nil, io.EOF + } + tsPrefix = append(tsPrefix, tsSuffix...) + } + ts, err = time.Parse(KubernetesTimezoneLogTimeFormat, string(tsPrefix[0:len(tsPrefix)-1])) if err != nil { return time.Time{}, tsPrefix, errors2.Wrap(err, "parsing timestamp") } - return ts, tsPrefix, nil + return ts.UTC(), tsPrefix, nil } diff --git a/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs_test.go b/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs_test.go new file mode 100644 index 00000000000..084d819b7be --- /dev/null +++ b/pkg/tcl/testworkflowstcl/testworkflowcontroller/logs_test.go @@ -0,0 +1,43 @@ +// Copyright 2024 Testkube. +// +// Licensed as a Testkube Pro file under the Testkube Community +// License (the "License"); you may not use this file except in compliance with +// the License. You may obtain a copy of the License at +// +// https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt + +package testworkflowcontroller + +import ( + "bufio" + "bytes" + "io" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func Test_ReadTimestamp_UTC(t *testing.T) { + prefix := "2024-06-07T12:41:49.037275300Z " + message := "some-message" + buf := bufio.NewReader(bytes.NewBufferString(prefix + message)) + ts, byt, err := ReadTimestamp(buf) + rest, _ := io.ReadAll(buf) + assert.NoError(t, err) + assert.Equal(t, []byte(prefix), byt) + assert.Equal(t, []byte(message), rest) + assert.Equal(t, time.Date(2024, 6, 7, 12, 41, 49, 37275300, time.UTC), ts) +} + +func Test_ReadTimestamp_NonUTC(t *testing.T) { + prefix := "2024-06-07T15:41:49.037275300+03:00 " + message := "some-message" + buf := bufio.NewReader(bytes.NewBufferString(prefix + message)) + ts, byt, err := ReadTimestamp(buf) + rest, _ := io.ReadAll(buf) + assert.NoError(t, err) + assert.Equal(t, []byte(prefix), byt) + assert.Equal(t, []byte(message), rest) + assert.Equal(t, time.Date(2024, 6, 7, 12, 41, 49, 37275300, time.UTC), ts) +} diff --git a/pkg/tcl/testworkflowstcl/testworkflowcontroller/utils.go b/pkg/tcl/testworkflowstcl/testworkflowcontroller/utils.go index 1b59f8cc142..506d361a100 100644 --- a/pkg/tcl/testworkflowstcl/testworkflowcontroller/utils.go +++ b/pkg/tcl/testworkflowstcl/testworkflowcontroller/utils.go @@ -20,7 +20,8 @@ import ( ) const ( - KubernetesLogTimeFormat = "2006-01-02T15:04:05.000000000Z" + KubernetesLogTimeFormat = "2006-01-02T15:04:05.000000000Z" + KubernetesTimezoneLogTimeFormat = KubernetesLogTimeFormat + "07:00" ) func GetEventContainerName(event *corev1.Event) string {