diff --git a/api/v1/diagnostic.proto b/api/v1/diagnostic.proto index c3a4662..2c8f02f 100644 --- a/api/v1/diagnostic.proto +++ b/api/v1/diagnostic.proto @@ -13,8 +13,8 @@ service Diagnostic { rpc Screenshot (ScreenshotRequest) returns (ScreenshotResponse); rpc ClearSystemEventLog (ClearSystemEventLogRequest) returns (ClearSystemEventLogResponse); rpc SendNMI (SendNMIRequest) returns (google.protobuf.Empty); - rpc GetSystemEventLog (GetSystemEventLogRequest) returns (GetSystemEventLogResponse); - rpc GetSystemEventLogRaw (GetSystemEventLogRawRequest) returns (GetSystemEventLogRawResponse); + rpc SystemEventLog (SystemEventLogRequest) returns (SystemEventLogResponse); + rpc SystemEventLogRaw (SystemEventLogRawRequest) returns (SystemEventLogRawResponse); } message ScreenshotRequest { @@ -40,7 +40,7 @@ message SendNMIRequest { v1.Authn authn = 1; } -message GetSystemEventLogRequest { +message SystemEventLogRequest { v1.Authn authn = 1; v1.Vendor vendor = 2; } @@ -52,15 +52,15 @@ message SystemEventLogEntry { string message = 4; } -message GetSystemEventLogResponse { +message SystemEventLogResponse { repeated SystemEventLogEntry events = 1; } -message GetSystemEventLogRawRequest { +message SystemEventLogRawRequest { v1.Authn authn = 1; v1.Vendor vendor = 2; } -message GetSystemEventLogRawResponse { +message SystemEventLogRawResponse { string log = 1; } diff --git a/client/client.go b/client/client.go index 488508e..92684e4 100644 --- a/client/client.go +++ b/client/client.go @@ -150,13 +150,14 @@ func ClearSystemEventLog(ctx context.Context, client v1.DiagnosticClient, taskCl func SendNMI(ctx context.Context, client v1.DiagnosticClient, request *v1.SendNMIRequest) error { _, err := client.SendNMI(ctx, request) return err +} -// GetSystemEventLog retrieves the System Event Log of the server. -func GetSystemEventLog(ctx context.Context, client v1.DiagnosticClient, request *v1.GetSystemEventLogRequest) (*v1.GetSystemEventLogResponse, error) { - return client.GetSystemEventLog(ctx, request) +// SystemEventLog retrieves the System Event Log of the server. +func SystemEventLog(ctx context.Context, client v1.DiagnosticClient, request *v1.SystemEventLogRequest) (*v1.SystemEventLogResponse, error) { + return client.SystemEventLog(ctx, request) } -// GetSystemEventLogRaw retrieves the System Event Log of the server. -func GetSystemEventLogRaw(ctx context.Context, client v1.DiagnosticClient, request *v1.GetSystemEventLogRawRequest) (*v1.GetSystemEventLogRawResponse, error) { - return client.GetSystemEventLogRaw(ctx, request) +// SystemEventLogRaw retrieves the System Event Log of the server. +func SystemEventLogRaw(ctx context.Context, client v1.DiagnosticClient, request *v1.SystemEventLogRawRequest) (*v1.SystemEventLogRawResponse, error) { + return client.SystemEventLogRaw(ctx, request) } diff --git a/cmd/sel.go b/cmd/sel.go index efed567..a8aee27 100644 --- a/cmd/sel.go +++ b/cmd/sel.go @@ -79,7 +79,7 @@ var ( defer conn.Close() client := v1.NewDiagnosticClient(conn) - resp, err := v1Client.GetSystemEventLog(ctx, client, &v1.GetSystemEventLogRequest{ + resp, err := v1Client.SystemEventLog(ctx, client, &v1.SystemEventLogRequest{ Authn: &v1.Authn{ Authn: &v1.Authn_DirectAuthn{ DirectAuthn: &v1.DirectAuthn{ @@ -123,7 +123,7 @@ var ( defer conn.Close() client := v1.NewDiagnosticClient(conn) - resp, err := v1Client.GetSystemEventLogRaw(ctx, client, &v1.GetSystemEventLogRawRequest{ + resp, err := v1Client.SystemEventLogRaw(ctx, client, &v1.SystemEventLogRawRequest{ Authn: &v1.Authn{ Authn: &v1.Authn_DirectAuthn{ DirectAuthn: &v1.DirectAuthn{ diff --git a/grpc/oob/diagnostic/diagnostic.go b/grpc/oob/diagnostic/diagnostic.go index 63daae1..d58388b 100644 --- a/grpc/oob/diagnostic/diagnostic.go +++ b/grpc/oob/diagnostic/diagnostic.go @@ -8,13 +8,13 @@ import ( type Action struct { common.Accessory - ScreenshotRequest *v1.ScreenshotRequest - ClearSystemEventLogRequest *v1.ClearSystemEventLogRequest - SendNMIRequest *v1.SendNMIRequest - ScreenshotRequest *v1.ScreenshotRequest - ClearSystemEventLogRequest *v1.ClearSystemEventLogRequest - GetSystemEventLogRequest *v1.GetSystemEventLogRequest - GetSystemEventLogRawRequest *v1.GetSystemEventLogRawRequest + ScreenshotRequest *v1.ScreenshotRequest + ClearSystemEventLogRequest *v1.ClearSystemEventLogRequest + SendNMIRequest *v1.SendNMIRequest + SystemEventLogRequest *v1.SystemEventLogRequest + SystemEventLogRawRequest *v1.SystemEventLogRawRequest + ActionName string + RPCName string } // WithLogger adds a logr to an Action struct. @@ -33,5 +33,14 @@ func WithStatusMessage(s chan string) Option { } } +// WithLabels adds the custom tracing and logging labels to an Action struct. +func WithLabels(actionName string, rpcName string) Option { + return func(a *Action) error { + a.ActionName = actionName + a.RPCName = rpcName + return nil + } +} + // Option to add to an Actions. type Option func(a *Action) error diff --git a/grpc/oob/diagnostic/getsel.go b/grpc/oob/diagnostic/getsel.go index 9839eae..1a4fd44 100644 --- a/grpc/oob/diagnostic/getsel.go +++ b/grpc/oob/diagnostic/getsel.go @@ -18,53 +18,50 @@ import ( "go.opentelemetry.io/otel/trace" ) -func NewSystemEventLogGetter(req *v1.GetSystemEventLogRequest, opts ...Option) (*Action, error) { +func NewSystemEventLogAction(req interface{}, opts ...Option) (*Action, error) { a := &Action{} - a.GetSystemEventLogRequest = req - for _, opt := range opts { - err := opt(a) - if err != nil { - return nil, err - } + switch r := req.(type) { + case *v1.SystemEventLogRequest: + a.SystemEventLogRequest = r + case *v1.SystemEventLogRawRequest: + a.SystemEventLogRawRequest = r + default: + return nil, fmt.Errorf("unsupported request type") } - return a, nil -} -func NewSystemEventLogRawGetter(req *v1.GetSystemEventLogRawRequest, opts ...Option) (*Action, error) { - a := &Action{} - a.GetSystemEventLogRawRequest = req for _, opt := range opts { err := opt(a) if err != nil { return nil, err } } + return a, nil } -func (m Action) GetSystemEventLog(ctx context.Context) (result bmc.SystemEventLogEntries, err error) { +func (m Action) SystemEventLog(ctx context.Context) (entries bmc.SystemEventLogEntries, raw string, err error) { labels := prometheus.Labels{ "service": "diagnostic", - "action": "get_system_event_log", + "action": m.ActionName, } timer := prometheus.NewTimer(metrics.ActionDuration.With(labels)) defer timer.ObserveDuration() tracer := otel.Tracer("pbnj") - ctx, span := tracer.Start(ctx, "diagnostic.GetSystemEventLog", trace.WithAttributes( - attribute.String("bmc.device", m.GetSystemEventLogRequest.GetAuthn().GetDirectAuthn().GetHost().GetHost()), + ctx, span := tracer.Start(ctx, "diagnostic."+m.RPCName, trace.WithAttributes( + attribute.String("bmc.device", m.SystemEventLogRequest.GetAuthn().GetDirectAuthn().GetHost().GetHost()), )) defer span.End() - if v := m.GetSystemEventLogRequest.GetVendor(); v != nil { + if v := m.SystemEventLogRequest.GetVendor(); v != nil { span.SetAttributes(attribute.String("bmc.vendor", v.GetName())) } - host, user, password, parseErr := m.ParseAuth(m.GetSystemEventLogRequest.GetAuthn()) + host, user, password, parseErr := m.ParseAuth(m.SystemEventLogRequest.GetAuthn()) if parseErr != nil { span.SetStatus(codes.Error, "error parsing credentials: "+parseErr.Error()) - return result, parseErr + return entries, raw, parseErr } span.SetAttributes(attribute.String("bmc.host", host), attribute.String("bmc.username", user)) @@ -75,88 +72,17 @@ func (m Action) GetSystemEventLog(ctx context.Context) (result bmc.SystemEventLo } client := bmclib.NewClient(host, user, password, opts...) - client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetSystemEventLog) - - m.SendStatusMessage("connecting to BMC") - err = client.Open(ctx) - meta := client.GetMetadata() - span.SetAttributes(attribute.StringSlice("bmc.open.providersAttempted", meta.ProvidersAttempted), - attribute.StringSlice("bmc.open.successfulOpenConns", meta.SuccessfulOpenConns)) - if err != nil { - span.SetStatus(codes.Error, err.Error()) - return nil, &repository.Error{ - Code: v1.Code_value["PERMISSION_DENIED"], - Message: err.Error(), - } - } - log := m.Log.WithValues("host", host, "user", user) - defer func() { - client.Close(ctx) - log.Info("closed connections", logMetadata(client.GetMetadata())...) - }() - log.Info("connected to BMC", logMetadata(client.GetMetadata())...) - m.SendStatusMessage("connected to BMC") - - // Get the system event log - m.SendStatusMessage("getting system event log") - sel, err := client.GetSystemEventLog(ctx) - log = m.Log.WithValues(logMetadata(client.GetMetadata())...) - meta = client.GetMetadata() - span.SetAttributes(attribute.StringSlice("bmc.get_system_event_log.providersAttempted", meta.ProvidersAttempted), - attribute.StringSlice("bmc.get_system_event_log.successfulOpenConns", meta.SuccessfulOpenConns)) - if err != nil { - log.Error(err, "error getting system event log") - span.SetStatus(codes.Error, "error getting system event log: "+err.Error()) - m.SendStatusMessage(fmt.Sprintf("failed to get system event log %v", host)) - - return nil, &repository.Error{ - Code: v1.Code_value["UNKNOWN"], - Message: err.Error(), - } - } - - span.SetStatus(codes.Ok, "") - log.Info("got system event log", logMetadata(client.GetMetadata())...) - m.SendStatusMessage(fmt.Sprintf("got system event log on %v", host)) - - return sel, nil -} - -func (m Action) GetSystemEventLogRaw(ctx context.Context) (result string, err error) { - labels := prometheus.Labels{ - "service": "diagnostic", - "action": "get_system_event_log_raw", - } - - timer := prometheus.NewTimer(metrics.ActionDuration.With(labels)) - defer timer.ObserveDuration() - - tracer := otel.Tracer("pbnj") - ctx, span := tracer.Start(ctx, "diagnostic.GetSystemEventLogRaw", trace.WithAttributes( - attribute.String("bmc.device", m.GetSystemEventLogRawRequest.GetAuthn().GetDirectAuthn().GetHost().GetHost()), - )) - defer span.End() - if v := m.GetSystemEventLogRawRequest.GetVendor(); v != nil { - span.SetAttributes(attribute.String("bmc.vendor", v.GetName())) + // Set the driver(s) to use based on the request type + switch { + case m.SystemEventLogRequest != nil: + client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetSystemEventLog) + case m.SystemEventLogRawRequest != nil: + client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetSystemEventLogRaw) + default: + return entries, raw, fmt.Errorf("unsupported request type") } - host, user, password, parseErr := m.ParseAuth(m.GetSystemEventLogRawRequest.GetAuthn()) - if parseErr != nil { - span.SetStatus(codes.Error, "error parsing credentials: "+parseErr.Error()) - return result, parseErr - } - - span.SetAttributes(attribute.String("bmc.host", host), attribute.String("bmc.username", user)) - - opts := []bmclib.Option{ - bmclib.WithLogger(m.Log), - bmclib.WithPerProviderTimeout(common.BMCTimeoutFromCtx(ctx)), - } - - client := bmclib.NewClient(host, user, password, opts...) - client.Registry.Drivers = client.Registry.Supports(providers.FeatureGetSystemEventLogRaw) - m.SendStatusMessage("connecting to BMC") err = client.Open(ctx) meta := client.GetMetadata() @@ -164,7 +90,7 @@ func (m Action) GetSystemEventLogRaw(ctx context.Context) (result string, err er attribute.StringSlice("bmc.open.successfulOpenConns", meta.SuccessfulOpenConns)) if err != nil { span.SetStatus(codes.Error, err.Error()) - return "", &repository.Error{ + return entries, raw, &repository.Error{ Code: v1.Code_value["PERMISSION_DENIED"], Message: err.Error(), } @@ -177,27 +103,37 @@ func (m Action) GetSystemEventLogRaw(ctx context.Context) (result string, err er log.Info("connected to BMC", logMetadata(client.GetMetadata())...) m.SendStatusMessage("connected to BMC") - // Get the system event log - m.SendStatusMessage("getting system event log") - sel, err := client.GetSystemEventLogRaw(ctx) + m.SendStatusMessage("getting " + m.ActionName + " on " + host) + + switch { + case m.SystemEventLogRequest != nil: + // Get the system event log + entries, err = client.GetSystemEventLog(ctx) + case m.SystemEventLogRawRequest != nil: + // Get the system event log + raw, err = client.GetSystemEventLogRaw(ctx) + default: + return entries, raw, fmt.Errorf("unsupported request type") + } + log = m.Log.WithValues(logMetadata(client.GetMetadata())...) meta = client.GetMetadata() - span.SetAttributes(attribute.StringSlice("bmc.get_system_event_log_raw.providersAttempted", meta.ProvidersAttempted), - attribute.StringSlice("bmc.get_system_event_log_raw.successfulOpenConns", meta.SuccessfulOpenConns)) + span.SetAttributes(attribute.StringSlice("bmc."+m.ActionName+".providersAttempted", meta.ProvidersAttempted), + attribute.StringSlice("bmc."+m.ActionName+".successfulOpenConns", meta.SuccessfulOpenConns)) if err != nil { - log.Error(err, "error getting raw system event log") - span.SetStatus(codes.Error, "error getting raw system event log: "+err.Error()) - m.SendStatusMessage(fmt.Sprintf("failed to get raw system event log %v", host)) + log.Error(err, "error getting "+m.ActionName) + span.SetStatus(codes.Error, "error getting "+m.ActionName+": "+err.Error()) + m.SendStatusMessage(fmt.Sprintf("failed to get "+m.ActionName+" %v", host)) - return "", &repository.Error{ + return entries, raw, &repository.Error{ Code: v1.Code_value["UNKNOWN"], Message: err.Error(), } } span.SetStatus(codes.Ok, "") - log.Info("got raw system event log", logMetadata(client.GetMetadata())...) - m.SendStatusMessage(fmt.Sprintf("got raw system event log on %v", host)) + log.Info("got "+m.ActionName, logMetadata(client.GetMetadata())...) + m.SendStatusMessage(fmt.Sprintf("got "+m.ActionName+" on %v", host)) - return sel, nil + return entries, raw, nil } diff --git a/grpc/rpc/diagnostic.go b/grpc/rpc/diagnostic.go index 221bc4d..dbda509 100644 --- a/grpc/rpc/diagnostic.go +++ b/grpc/rpc/diagnostic.go @@ -4,6 +4,7 @@ import ( "context" "time" + "github.com/bmc-toolbox/bmclib/v2/bmc" "github.com/rs/xid" v1 "github.com/tinkerbell/pbnj/api/v1" "github.com/tinkerbell/pbnj/grpc/oob/diagnostic" @@ -106,8 +107,9 @@ func (d *DiagnosticService) SendNMI(ctx context.Context, in *v1.SendNMIRequest) } return empty, nil +} -func (d *DiagnosticService) GetSystemEventLog(ctx context.Context, in *v1.GetSystemEventLogRequest) (*v1.GetSystemEventLogResponse, error) { +func (d *DiagnosticService) SystemEventLog(ctx context.Context, in *v1.SystemEventLogRequest) (*v1.SystemEventLogResponse, error) { l := logging.ExtractLogr(ctx) l.Info("start Get System Event Log request", @@ -115,55 +117,70 @@ func (d *DiagnosticService) GetSystemEventLog(ctx context.Context, in *v1.GetSys "vendor", in.Vendor.GetName(), ) - selgetter, err := diagnostic.NewSystemEventLogGetter(in, diagnostic.WithLogger(l)) + selaction, err := diagnostic.NewSystemEventLogAction(in, diagnostic.WithLogger(l), + diagnostic.WithLabels("system_event_log", "SystemEventLog")) if err != nil { - l.Error(err, "error creating system event log getter") + l.Error(err, "error creating system event log action") return nil, err } - entries, err := selgetter.GetSystemEventLog(ctx) + entries, _, err := selaction.SystemEventLog(ctx) if err != nil { l.Error(err, "error getting system event log") return nil, err } - var events []*v1.SystemEventLogEntry - - for _, entry := range entries { - events = append(events, &v1.SystemEventLogEntry{ - Id: entry[0], - Timestamp: entry[1], - Description: entry[2], - Message: entry[3], - }) - } + events := convertEntriesToEvents(entries) - return &v1.GetSystemEventLogResponse{ + return &v1.SystemEventLogResponse{ Events: events, }, nil } -func (d *DiagnosticService) GetSystemEventLogRaw(ctx context.Context, in *v1.GetSystemEventLogRawRequest) (*v1.GetSystemEventLogRawResponse, error) { +func (d *DiagnosticService) SystemEventLogRaw(ctx context.Context, in *v1.SystemEventLogRawRequest) (*v1.SystemEventLogRawResponse, error) { l := logging.ExtractLogr(ctx) - l.Info("start Get System Event Log request", + l.Info("start Get System Event Log Raw request", "username", in.Authn.GetDirectAuthn().GetUsername(), "vendor", in.Vendor.GetName(), ) - rawselgetter, err := diagnostic.NewSystemEventLogRawGetter(in, diagnostic.WithLogger(l)) + rawselaction, err := diagnostic.NewSystemEventLogAction(in, diagnostic.WithLogger(l), + diagnostic.WithLabels("system_event_log_raw", "SystemEventLogRaw")) if err != nil { - l.Error(err, "error creating raw system event log getter") + l.Error(err, "error creating raw system event log action") return nil, err } - eventlog, err := rawselgetter.GetSystemEventLogRaw(ctx) + _, eventlog, err := rawselaction.SystemEventLog(ctx) if err != nil { l.Error(err, "error getting raw system event log") return nil, err } - return &v1.GetSystemEventLogRawResponse{ + return &v1.SystemEventLogRawResponse{ Log: eventlog, }, nil } + +func convertEntriesToEvents(entries bmc.SystemEventLogEntries) []*v1.SystemEventLogEntry { + var events []*v1.SystemEventLogEntry + + if len(entries) == 0 { + return events + } + + for _, entry := range entries { + if len(entry) < 4 { + continue + } + events = append(events, &v1.SystemEventLogEntry{ + Id: entry[0], + Timestamp: entry[1], + Description: entry[2], + Message: entry[3], + }) + } + + return events +} diff --git a/grpc/rpc/diagnostic_test.go b/grpc/rpc/diagnostic_test.go index 950e210..e9d2f02 100644 --- a/grpc/rpc/diagnostic_test.go +++ b/grpc/rpc/diagnostic_test.go @@ -5,7 +5,9 @@ import ( "errors" "testing" + "github.com/bmc-toolbox/bmclib/v2/bmc" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" "github.com/philippgille/gokv" "github.com/philippgille/gokv/freecache" @@ -14,6 +16,17 @@ import ( "github.com/tinkerbell/pbnj/grpc/taskrunner" ) +type MockDiagnosticAction struct { + SystemEventLogFunc func(ctx context.Context) (entries []*v1.SystemEventLogEntry, raw string, err error) +} + +func (m *MockDiagnosticAction) SystemEventLog(ctx context.Context) (entries []*v1.SystemEventLogEntry, raw string, err error) { + if m.SystemEventLogFunc != nil { + return m.SystemEventLogFunc(ctx) + } + return nil, "", nil +} + func TestClearSystemEventLog(t *testing.T) { testCases := []struct { name string @@ -84,3 +97,176 @@ func TestClearSystemEventLog(t *testing.T) { }) } } +func TestConvertEntriesToEvents(t *testing.T) { + testCases := []struct { + name string + entries bmc.SystemEventLogEntries + expectedEvents []*v1.SystemEventLogEntry + }{ + { + name: "empty entries", + entries: bmc.SystemEventLogEntries{}, + expectedEvents: nil, + }, + { + name: "valid entries", + entries: bmc.SystemEventLogEntries{ + {"1", "2022-01-01", "Event 1", "Message 1"}, + {"2", "2022-01-02", "Event 2", "Message 2"}, + }, + expectedEvents: []*v1.SystemEventLogEntry{ + { + Id: "1", + Timestamp: "2022-01-01", + Description: "Event 1", + Message: "Message 1", + }, + { + Id: "2", + Timestamp: "2022-01-02", + Description: "Event 2", + Message: "Message 2", + }, + }, + }, + { + name: "invalid entries", + entries: bmc.SystemEventLogEntries{ + {"1", "2022-01-01", "Event 1"}, + {"2", "2022-01-02", "Event 2", "Message 2"}, + }, + expectedEvents: []*v1.SystemEventLogEntry{ + { + Id: "2", + Timestamp: "2022-01-02", + Description: "Event 2", + Message: "Message 2", + }, + }, + }, + } + + for _, tc := range testCases { + testCase := tc + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + events := convertEntriesToEvents(testCase.entries) + + if diff := cmp.Diff(testCase.expectedEvents, events, cmpopts.IgnoreUnexported(v1.SystemEventLogEntry{})); diff != "" { + t.Errorf("Mismatch (-expected, +actual):\n%s", diff) + } + }) + } +} +func TestSystemEventLog(t *testing.T) { + testCases := []struct { + name string + req *v1.SystemEventLogRequest + expectedEvents []*v1.SystemEventLogEntry + expectedErr error + }{ + { + name: "success", + req: &v1.SystemEventLogRequest{ + Authn: &v1.Authn{ + Authn: &v1.Authn_DirectAuthn{ + DirectAuthn: &v1.DirectAuthn{ + Username: "testuser", + }, + }, + }, + Vendor: &v1.Vendor{ + Name: "testvendor", + }, + }, + expectedEvents: []*v1.SystemEventLogEntry{ + { + Id: "1", + Timestamp: "2022-01-01", + Description: "Event 1", + Message: "Message 1", + }, + { + Id: "2", + Timestamp: "2022-01-02", + Description: "Event 2", + Message: "Message 2", + }, + }, + expectedErr: nil, + }, + { + name: "error creating system event log action", + req: &v1.SystemEventLogRequest{ + Authn: &v1.Authn{ + Authn: &v1.Authn_DirectAuthn{ + DirectAuthn: &v1.DirectAuthn{ + Username: "testuser", + }, + }, + }, + Vendor: &v1.Vendor{ + Name: "testvendor", + }, + }, + expectedEvents: nil, + expectedErr: errors.New("error creating system event log action"), + }, + { + name: "error getting system event log", + req: &v1.SystemEventLogRequest{ + Authn: &v1.Authn{ + Authn: &v1.Authn_DirectAuthn{ + DirectAuthn: &v1.DirectAuthn{ + Username: "testuser", + }, + }, + }, + Vendor: &v1.Vendor{ + Name: "testvendor", + }, + }, + expectedEvents: nil, + expectedErr: errors.New("error getting system event log"), + }, + } + + for _, tc := range testCases { + testCase := tc + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + diagnosticService := &MockDiagnosticAction{ + SystemEventLogFunc: func(ctx context.Context) (entries []*v1.SystemEventLogEntry, raw string, err error) { + if testCase.expectedErr != nil { + return nil, "", testCase.expectedErr + } + return []*v1.SystemEventLogEntry{ + {Id: "1", Timestamp: "2022-01-01", Description: "Event 1", Message: "Message 1"}, + {Id: "2", Timestamp: "2022-01-02", Description: "Event 2", Message: "Message 2"}, + }, "", nil + }, + } + + response, _, err := diagnosticService.SystemEventLog(ctx) + + t.Log("Got : ", response) + if err != nil { + if testCase.expectedErr == nil { + t.Fatalf("Unexpected error: %v", err) + } else { + if diff := cmp.Diff(testCase.expectedErr.Error(), err.Error()); diff != "" { + t.Fatalf("Error mismatch (-expected, +actual):\n%s", diff) + } + } + } else { + if diff := cmp.Diff(testCase.expectedEvents, response, cmpopts.IgnoreUnexported(v1.SystemEventLogEntry{})); diff != "" { + t.Fatalf("Events mismatch (-expected, +actual):\n%s", diff) + } + } + }) + } +}