@@ -112,7 +112,7 @@ func TestObjectSync(t *testing.T) {
112112 t .Run ("Host" , func (t * testing.T ) {
113113 t .Parallel ()
114114
115- for hostId , host := range data .Hosts {
115+ for _ , host := range data .Hosts {
116116 t .Run ("Verify-" + host .VariantInfoString (), func (t * testing.T ) {
117117 t .Parallel ()
118118
@@ -137,23 +137,13 @@ func TestObjectSync(t *testing.T) {
137137 }
138138 })
139139
140- t .Run ("Verify-SlaLifeCycle-" + fmt .Sprint (hostId ), func (t * testing.T ) {
141- eventually .Assert (t , func (t require.TestingT ) {
142- var count int
143- stmt := `SELECT COUNT(*) FROM "sla_lifecycle" INNER JOIN "host" ON "host"."id"="sla_lifecycle"."host_id" WHERE "service_id" IS NULL AND "host"."name"=?`
144- err := db .Get (& count , db .Rebind (stmt ), host .Name )
145-
146- require .NoError (t , err , "querying host sla lifecycle count should not fail" )
147- require .True (t , count == 1 , "there should be one sla lifecycle entry for host %q" , host .Name )
148- }, 20 * time .Second , 1 * time .Second )
149- })
150140 }
151141 })
152142
153143 t .Run ("Service" , func (t * testing.T ) {
154144 t .Parallel ()
155145
156- for serviceId , service := range data .Services {
146+ for _ , service := range data .Services {
157147 t .Run ("Verify-" + service .VariantInfoString (), func (t * testing.T ) {
158148 t .Parallel ()
159149
@@ -177,18 +167,41 @@ func TestObjectSync(t *testing.T) {
177167 })
178168 }
179169 })
170+ }
171+ })
180172
181- t .Run ("Verify-SlaLifeCycle-" + fmt .Sprint (serviceId ), func (t * testing.T ) {
182- eventually .Assert (t , func (t require.TestingT ) {
183- var count int
184- stmt := `SELECT COUNT(*) FROM "sla_lifecycle" INNER JOIN "service" ON "service"."id"="sla_lifecycle"."service_id" WHERE "service"."name" = ?`
185- err := db .Get (& count , db .Rebind (stmt ), service .Name )
173+ t .Run ("SlaLifeCycle" , func (t * testing.T ) {
174+ t .Parallel ()
186175
187- require .NoError (t , err , "querying service sla lifecycle should not fail" )
188- require .True (t , count == 1 , "there should be one sla lifecycle entry for service %q" , service .Name )
189- }, 20 * time .Second , 1 * time .Second )
190- })
191- }
176+ slinfo := & SlaLifecycle {CreateTime : types .UnixMilli (time .Now ())}
177+
178+ t .Run ("Hosts" , func (t * testing.T ) {
179+ t .Parallel ()
180+
181+ for hostId , host := range data .Hosts {
182+ t .Run ("Verify-Host-" + fmt .Sprint (hostId ), func (t * testing.T ) {
183+ t .Parallel ()
184+
185+ eventually .Assert (t , func (t require.TestingT ) {
186+ verifySlaLifeCycleRow (t , db , slinfo , host .Name , "" )
187+ }, 20 * time .Second , 1 * time .Second )
188+ })
189+ }
190+ })
191+
192+ t .Run ("Services" , func (t * testing.T ) {
193+ t .Parallel ()
194+
195+ for serviceId , service := range data .Services {
196+ t .Run ("Verify-Service-" + fmt .Sprint (serviceId ), func (t * testing.T ) {
197+ t .Parallel ()
198+
199+ eventually .Assert (t , func (t require.TestingT ) {
200+ verifySlaLifeCycleRow (t , db , slinfo , * service .HostName , service .Name )
201+ }, 20 * time .Second , 1 * time .Second )
202+ })
203+ }
204+ })
192205 })
193206
194207 t .Run ("HostGroup" , func (t * testing.T ) {
@@ -379,22 +392,6 @@ func TestObjectSync(t *testing.T) {
379392 require .NoError (t , err , "querying service count should not fail" )
380393 return count == 0
381394 }, 20 * time .Second , 1 * time .Second , "service with name=%q should be removed from database" , service .Name )
382-
383- eventually .Assert (t , func (t require.TestingT ) {
384- var expectedResult []struct {
385- CreateTime types.UnixMilli `db:"create_time"`
386- DeleteTime types.UnixMilli `db:"delete_time"`
387- }
388- stmt := `SELECT "create_time", "delete_time" FROM "sla_lifecycle"
389- INNER JOIN "service" ON "service"."id"="sla_lifecycle"."service_id"
390- WHERE "service"."name" = ?`
391- err := db .Select (& expectedResult , db .Rebind (stmt ), service .Name )
392- require .NoError (t , err , "querying service sla lifecycle should not fail" )
393-
394- require .True (t , len (expectedResult ) == 1 )
395- require .False (t , expectedResult [0 ].CreateTime .Time ().IsZero ())
396- require .False (t , expectedResult [0 ].DeleteTime .Time ().IsZero ())
397- }, 20 * time .Second , 1 * time .Second )
398395 })
399396 }
400397
@@ -452,6 +449,34 @@ func TestObjectSync(t *testing.T) {
452449 })
453450 })
454451
452+ t .Run ("SlaLifeCycle" , func (t * testing.T ) {
453+ t .Parallel ()
454+
455+ for serviceId , service := range makeTestSyncServices (t ) {
456+ //service.Name += fmt.Sprint(serviceId)
457+
458+ t .Run ("Verify-Service-" + fmt .Sprint (serviceId ), func (t * testing.T ) {
459+ t .Parallel ()
460+
461+ client .CreateObject (t , "services" , * service .HostName + "!" + service .Name , map [string ]interface {}{
462+ "attrs" : makeIcinga2ApiAttributes (service , false ),
463+ })
464+
465+ slinfo := & SlaLifecycle {CreateTime : types .UnixMilli (time .Now ())}
466+ eventually .Assert (t , func (t require.TestingT ) {
467+ verifySlaLifeCycleRow (t , db , slinfo , * service .HostName , service .Name )
468+ }, 20 * time .Second , 1 * time .Second )
469+
470+ client .DeleteObject (t , "services" , * service .HostName + "!" + service .Name , false )
471+
472+ slinfo .DeleteTime = types .UnixMilli (time .Now ())
473+ eventually .Assert (t , func (t require.TestingT ) {
474+ verifySlaLifeCycleRow (t , db , slinfo , "" , "" )
475+ }, 20 * time .Second , 1 * time .Second )
476+ })
477+ }
478+ })
479+
455480 t .Run ("User" , func (t * testing.T ) {
456481 t .Parallel ()
457482
@@ -1222,6 +1247,68 @@ func verifyIcingaDbRow(t require.TestingT, db *sqlx.DB, obj interface{}) {
12221247 require .False (t , rows .Next (), "SQL query should return only one row: %s" , query )
12231248}
12241249
1250+ func verifySlaLifeCycleRow (t require.TestingT , db * sqlx.DB , slinfo * SlaLifecycle , host string , service string ) {
1251+ query := `SELECT "create_time", "delete_time", "sla_lifecycle"."host_id", "sla_lifecycle"."service_id" FROM "sla_lifecycle"`
1252+ var args []interface {}
1253+ if ! slinfo .HostID .Valid () {
1254+ query += ` INNER JOIN "host" ON "host"."id"="sla_lifecycle"."host_id"`
1255+ where := ` WHERE "host"."name"=?`
1256+
1257+ args = append (args , host )
1258+ if service == "" {
1259+ where += ` AND "service_id" IS NULL`
1260+ } else {
1261+ query += ` INNER JOIN "service" ON "service"."id"="sla_lifecycle"."service_id"`
1262+ where += ` AND "service"."name"=?`
1263+ args = append (args , service )
1264+ }
1265+
1266+ query += where + ` AND "delete_time" = 0`
1267+ } else {
1268+ query += ` WHERE "host_id"=?`
1269+ args = []interface {}{slinfo .HostID }
1270+ if ! slinfo .ServiceID .Valid () {
1271+ query += ` AND "service_id" IS NULL`
1272+ } else {
1273+ query += ` AND "service_id"=?`
1274+ args = append (args , slinfo .ServiceID )
1275+ }
1276+ }
1277+
1278+ var resultSet []SlaLifecycle
1279+ err := db .Select (& resultSet , db .Rebind (query ), args ... )
1280+ require .NoError (t , err , "querying sla lifecycle should not fail: Query: %q" , query )
1281+
1282+ require .Len (t , resultSet , 1 , "there should be one sla lifecycle entry" )
1283+
1284+ result := resultSet [0 ]
1285+ zerotimestamp := time .Unix (0 , 0 )
1286+
1287+ require .NotEqual (t , zerotimestamp , result .CreateTime .Time ())
1288+ assert .WithinDuration (t , slinfo .CreateTime .Time (), result .CreateTime .Time (), time .Minute )
1289+
1290+ if slinfo .DeleteTime .Time ().IsZero () {
1291+ // We can't join on the host/service tables, as the sla lifecycle entries may reference entries that have
1292+ // already been deleted. So cache the host/service id to use as a filter when asserting the sla lifecycles
1293+ // delete event.
1294+ slinfo .HostID = result .HostID
1295+ slinfo .ServiceID = result .ServiceID
1296+
1297+ require .Equal (t , zerotimestamp , result .DeleteTime .Time ())
1298+ } else {
1299+ require .NotEqual (t , zerotimestamp , result .DeleteTime .Time ())
1300+ require .Less (t , result .CreateTime .Time (), result .DeleteTime .Time ())
1301+ assert .WithinDuration (t , slinfo .DeleteTime .Time (), result .DeleteTime .Time (), time .Minute )
1302+ }
1303+ }
1304+
1305+ type SlaLifecycle struct {
1306+ CreateTime types.UnixMilli `db:"create_time"`
1307+ DeleteTime types.UnixMilli `db:"delete_time"`
1308+ HostID types.Binary `db:"host_id"`
1309+ ServiceID types.Binary `db:"service_id"`
1310+ }
1311+
12251312// newString allocates a new *string and initializes it. This helper function exists as
12261313// there seems to be no way to achieve this within a single statement.
12271314func newString (s string ) * string {
0 commit comments