Documentation in literate-programming-style is available at:
https://redhatinsights.github.io/ccx-notification-writer/packages/differ/comparator_test.html
|
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/RedHatInsights/ccx-notification-service/differ"
"github.com/RedHatInsights/ccx-notification-service/tests/mocks"
"github.com/RedHatInsights/ccx-notification-service/types"
)
var (
statesList = [ ] types . State {
{
ID : 1 ,
Value : differ . NotificationStateSent ,
Comment : "sent state" ,
} ,
{
ID : 2 ,
Value : differ . NotificationStateSame ,
Comment : "same state" ,
} ,
{
ID : 3 ,
Value : differ . NotificationStateLower ,
Comment : "lower state" ,
} ,
{
ID : 4 ,
Value : differ . NotificationStateError ,
Comment : "error state" ,
} ,
}
notificationTypesListInstantOnly = [ ] types . NotificationType {
{
ID : 1 ,
Value : differ . NotificationTypeInstant ,
Frequency : "instant" ,
Comment : "instant notifs" ,
} ,
}
testCluster = types . ClusterEntry {
OrgID : 1 ,
AccountNumber : 0o123456 ,
ClusterName : "test_cluster1" ,
KafkaOffset : 0 ,
UpdatedAt : types . Timestamp ( testTimestamp ) ,
}
)
func TestGetState ( t * testing . T ) {
assert . Equal ( t , types . StateID ( 1 ) , differ . GetState ( statesList , differ . NotificationStateSent ) )
assert . Equal ( t , types . StateID ( 2 ) , differ . GetState ( statesList , differ . NotificationStateSame ) )
assert . Equal ( t , types . StateID ( 3 ) , differ . GetState ( statesList , differ . NotificationStateLower ) )
assert . Equal ( t , types . StateID ( 4 ) , differ . GetState ( statesList , differ . NotificationStateError ) )
assert . Equal ( t , types . StateID ( - 1 ) , differ . GetState ( statesList , "any_other_state" ) )
}
func TestGetStates ( t * testing . T ) {
storage := mocks . Storage { }
storage . On ( "ReadStates" ) . Return (
func ( ) [ ] types . State {
return statesList
} ,
func ( ) error {
return nil
} ,
)
assert . Nil ( t , differ . GetStates ( & storage ) )
assert . Equal ( t , types . StateID ( 2 ) , differ . States . SameState )
assert . Equal ( t , types . StateID ( 1 ) , differ . States . SentState )
assert . Equal ( t , types . StateID ( 3 ) , differ . States . LowerIssueState )
assert . Equal ( t , types . StateID ( 4 ) , differ . States . ErrorState )
}
func TestGetNotificationType ( t * testing . T ) {
assert . Equal ( t , types . NotificationTypeID ( 1 ) , differ . GetNotificationType ( notificationTypesListInstantOnly , differ . NotificationTypeInstant ) )
assert . Equal ( t , types . NotificationTypeID ( - 1 ) , differ . GetNotificationType ( notificationTypesListInstantOnly , "any_other_type" ) )
}
func TestGetNotifications ( t * testing . T ) {
storage := mocks . Storage { }
storage . On ( "ReadNotificationTypes" ) . Return (
func ( ) [ ] types . NotificationType {
return notificationTypesListInstantOnly
} ,
func ( ) error {
return nil
} ,
)
assert . Nil ( t , differ . GetNotificationTypes ( & storage ) )
assert . Equal ( t , types . NotificationTypeID ( 1 ) , differ . NotificationTypes . Instant )
|
reset it to not affect other tests
|
differ . NotificationTypes . Instant = 0
}
func TestIssuesEqualSameIssues ( t * testing . T ) {
issue1 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} }
issue2 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} }
assert . True ( t , differ . IssuesEqual ( & issue1 , & issue2 ) , "Compared issues should be equal" )
}
func TestIssuesEqualDifferentDetails ( t * testing . T ) {
issue1 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} }
issue2 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue is different" ) ,
} }
assert . True ( t , differ . IssuesEqual ( & issue1 , & issue2 ) , "Compared issues should be equal" )
}
func TestIssuesEqualDifferentModule ( t * testing . T ) {
issue1 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} }
issue2 := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} }
assert . False ( t , differ . IssuesEqual ( & issue1 , & issue2 ) , "Compared issues should not be equal" )
}
func TestNewIssueNotInOldReport ( t * testing . T ) {
oldReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
} ,
}
issue := types . EvaluatedReportItem { ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} }
assert . True ( t ,
differ . IssueNotInReport ( oldReport , & issue ) ,
"New issue not in old report old report, so result should be true." ,
)
}
func TestIssueNotInReportSameItemsInNewReport ( t * testing . T ) {
oldReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} ,
} ,
} ,
}
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} ,
} ,
} ,
}
for _ , issue := range newReport . Reports {
assert . False ( t ,
differ . IssueNotInReport ( oldReport , issue ) ,
"New report has the same items than old report, so comparison result should be false." ,
)
}
}
func TestIssueNotInReportSameLengthDifferentItemsInNewReport ( t * testing . T ) {
oldReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} ,
} ,
} ,
}
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_3.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue 3" ) ,
} ,
} ,
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_4.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue 4" ) ,
} ,
} ,
} ,
}
for _ , issue := range newReport . Reports {
assert . True ( t ,
differ . IssueNotInReport ( oldReport , issue ) ,
"New and old report have different items, so result should be true." ,
)
}
}
func TestIssueNotInReportLessItemsInNewReportAndIssueNotFoundInOldReports ( t * testing . T ) {
oldReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} ,
} ,
} ,
}
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_3.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the new issue" ) ,
} ,
} ,
} ,
}
for _ , issue := range newReport . Reports {
assert . True ( t ,
differ . IssueNotInReport ( oldReport , issue ) ,
"New report's issue has not been found in old report, so result should be true." ,
)
}
}
func TestIssueNotInReportLessItemsInNewReportAndIssueFoundInOldReports ( t * testing . T ) {
oldReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_2.report" ,
ErrorKey : "SOME_OTHER_ERROR_KEY" ,
Details : [ ] byte ( "details of the other issue" ) ,
} ,
} ,
} ,
}
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
} ,
}
for _ , issue := range newReport . Reports {
assert . False ( t ,
differ . IssueNotInReport ( oldReport , issue ) ,
"New report's issue has been found in old report, so result should be false." ,
)
}
}
func TestShouldNotifyNoPreviousRecord ( t * testing . T ) {
storage := mocks . Storage { }
storage . On ( "ReadLastNotifiedRecordForClusterList" ,
mock . AnythingOfType ( "[]types.ClusterEntry" ) ,
mock . AnythingOfType ( "string" ) ,
mock . AnythingOfType ( "types.EventTarget" ) ) .
Return (
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) types . NotifiedRecordsPerCluster {
return types . NotifiedRecordsPerCluster { }
} ,
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) error {
return nil
} ,
)
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_1.report" ,
ErrorKey : "SOME_ERROR_KEY" ,
Details : [ ] byte ( "details of the issue" ) ,
} ,
} ,
} ,
}
d := differ . Differ {
Target : types . NotificationBackendTarget ,
}
d . PreviouslyReported , _ = storage . ReadLastNotifiedRecordForClusterList ( make ( [ ] types . ClusterEntry , 0 ) , "24 hours" , types . NotificationBackendTarget )
for _ , issue := range newReport . Reports {
assert . True ( t , d . ShouldNotify ( testCluster , issue ) )
}
}
func TestShouldNotNotifySameRuleDifferentDetails ( t * testing . T ) {
storage := mocks . Storage { }
storage . On ( "ReadLastNotifiedRecordForClusterList" ,
mock . AnythingOfType ( "[]types.ClusterEntry" ) ,
mock . AnythingOfType ( "string" ) ,
mock . AnythingOfType ( "types.EventTarget" ) ) .
Return (
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) types . NotifiedRecordsPerCluster {
return types . NotifiedRecordsPerCluster {
types . ClusterOrgKey { OrgID : testCluster . OrgID , ClusterName : testCluster . ClusterName } : {
OrgID : testCluster . OrgID ,
AccountNumber : testCluster . AccountNumber ,
ClusterName : testCluster . ClusterName ,
UpdatedAt : types . Timestamp ( testTimestamp ) ,
NotificationTypeID : 1 ,
StateID : 1 ,
Report : "{\"analysis_metadata\":{\"metadata\":\"some metadata\"},\"reports\":[{\"rule_id\":\"rule_4|RULE_4\",\"component\":\"ccx_rules_ocp.external.rules.rule_4.report\",\"type\":\"rule\",\"key\":\"RULE_4\",\"details\":{\"degraded_operators\":[{\"available\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:45:10Z\",\"reason\":\"AsExpected\",\"message\":\"Available: 2 nodes are active; 1 nodes are at revision 0; 2 nodes are at revision 2; 0 nodes have achieved new revision 3\"},\"degraded\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:46:14Z\",\"reason\":\"NodeInstallerDegradedInstallerPodFailed\",\"message\":\"NodeControllerDegraded: All master nodes are ready\\nStaticPodsDegraded: nodes/ip-10-0-137-172.us-east-2.compute.internal pods/kube-apiserver-ip-10-0-137-172.us-east-2.compute.internal container=\\\"kube-apiserver-3\\\" is not ready\"},\"name\":\"kube-apiserver\",\"progressing\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:43:00Z\",\"reason\":\"\",\"message\":\"Progressing: 1 nodes are at revision 0; 2 nodes are at revision 2; 0 nodes have achieved new revision 3\"},\"upgradeable\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:42:52Z\",\"reason\":\"AsExpected\",\"message\":\"\"},\"version\":\"4.3.13\"}],\"type\":\"rule\",\"error_key\":\"NODE_INSTALLER_DEGRADED\"},\"tags\":[],\"links\":{\"kcs\":[\"https://access.redhat.com/solutions/4849711\"]}}]}" ,
NotifiedAt : types . Timestamp ( testTimestamp ) ,
ErrorLog : "" ,
} ,
}
} ,
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) error {
return nil
} ,
)
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem { Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.rule_4.report" ,
ErrorKey : "RULE_4" ,
Details : [ ] byte ( "The details differ somehow" ) ,
} ,
} ,
} ,
}
d := differ . Differ {
Target : types . NotificationBackendTarget ,
}
d . PreviouslyReported , _ = storage . ReadLastNotifiedRecordForClusterList ( make ( [ ] types . ClusterEntry , 0 ) , "24 hours" , types . NotificationBackendTarget )
for _ , issue := range newReport . Reports {
assert . False ( t , d . ShouldNotify ( testCluster , issue ) )
}
}
func TestShouldNotifyIssueNotFoundInPreviousRecords ( t * testing . T ) {
storage := mocks . Storage { }
storage . On ( "ReadLastNotifiedRecordForClusterList" ,
mock . AnythingOfType ( "[]types.ClusterEntry" ) ,
mock . AnythingOfType ( "string" ) ,
mock . AnythingOfType ( "types.EventTarget" ) ) .
Return (
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) types . NotifiedRecordsPerCluster {
return types . NotifiedRecordsPerCluster {
types . ClusterOrgKey { OrgID : testCluster . OrgID , ClusterName : testCluster . ClusterName } : {
OrgID : testCluster . OrgID ,
AccountNumber : testCluster . AccountNumber ,
ClusterName : testCluster . ClusterName ,
UpdatedAt : types . Timestamp ( testTimestamp ) ,
NotificationTypeID : 1 ,
StateID : 1 ,
Report : "{\"analysis_metadata\":{\"metadata\":\"some metadata\"},\"reports\":[{\"rule_id\":\"rule_4|RULE_4\",\"component\":\"ccx_rules_ocp.external.rules.rule_4.report\",\"type\":\"rule\",\"key\":\"RULE_4\",\"details\":{\"degraded_operators\":[{\"available\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:45:10Z\",\"reason\":\"AsExpected\",\"message\":\"Available: 2 nodes are active; 1 nodes are at revision 0; 2 nodes are at revision 2; 0 nodes have achieved new revision 3\"},\"degraded\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:46:14Z\",\"reason\":\"NodeInstallerDegradedInstallerPodFailed\",\"message\":\"NodeControllerDegraded: All master nodes are ready\\nStaticPodsDegraded: nodes/ip-10-0-137-172.us-east-2.compute.internal pods/kube-apiserver-ip-10-0-137-172.us-east-2.compute.internal container=\\\"kube-apiserver-3\\\" is not ready\"},\"name\":\"kube-apiserver\",\"progressing\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:43:00Z\",\"reason\":\"\",\"message\":\"Progressing: 1 nodes are at revision 0; 2 nodes are at revision 2; 0 nodes have achieved new revision 3\"},\"upgradeable\":{\"status\":true,\"last_trans_time\":\"2020-04-21T12:42:52Z\",\"reason\":\"AsExpected\",\"message\":\"\"},\"version\":\"4.3.13\"}],\"type\":\"rule\",\"error_key\":\"NODE_INSTALLER_DEGRADED\"},\"tags\":[],\"links\":{\"kcs\":[\"https://access.redhat.com/solutions/4849711\"]}}]}" ,
NotifiedAt : types . Timestamp ( testTimestamp ) ,
ErrorLog : "" ,
} ,
}
} ,
func ( clusterEntries [ ] types . ClusterEntry , timeOffset string , eventTarget types . EventTarget ) error {
return nil
} ,
)
newReport := types . Report {
Reports : types . ReportContent {
{
ReportItem : types . ReportItem {
Type : "rule" ,
Module : "ccx_rules_ocp.external.rules.new_rule.report" ,
ErrorKey : "NEW_RULE_NOT_PREVIOUSLY_REPORTED" ,
Details : [ ] byte ( "New rule with bunch of details" ) ,
} ,
} ,
} ,
}
d := differ . Differ {
Target : types . NotificationBackendTarget ,
}
d . PreviouslyReported , _ = storage . ReadLastNotifiedRecordForClusterList ( make ( [ ] types . ClusterEntry , 0 ) , "24 hours" , types . NotificationBackendTarget )
for _ , issue := range newReport . Reports {
assert . True ( t , d . ShouldNotify ( testCluster , issue ) )
}
}
|