Repository: aquasecurity/starboard
Pull request #1015 (2022-03-10 07:08:56)

fix: use ttl check with date util
- consolidate ttl checks with date util to avoid code duplication

codecov[bot]: # [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) Report
> Merging [#1015](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (5357c8d) into [main](https://codecov.io/gh/aquasecurity/starboard/commit/443d1a9989333cb685ed8a172ed5cb8784f0cf33?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) (443d1a9) will **decrease** coverage by `16.70%`.
> The diff coverage is `50.00%`.

[![Impacted file tree graph](https://codecov.io/gh/aquasecurity/starboard/pull/1015/graphs/tree.svg?width=650&height=150&src=pr&token=qqTGKAJ0Wb&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)

```diff
@@             Coverage Diff             @@
##             main    #1015       +/-   ##
===========================================
- Coverage   57.89%   41.19%   -16.71%     
===========================================
  Files          70       53       -17     
  Lines        9097     7870     -1227     
===========================================
- Hits         5267     3242     -2025     
- Misses       3300     4433     +1133     
+ Partials      530      195      -335     
```


| [Impacted Files](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | Coverage Δ | |
|---|---|---|
| [pkg/operator/controller/ttl\_report.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL29wZXJhdG9yL2NvbnRyb2xsZXIvdHRsX3JlcG9ydC5nbw==) | `0.00% <0.00%> (-16.95%)` | :arrow_down: |
| [pkg/utils/dateutil.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3V0aWxzL2RhdGV1dGlsLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/plugin/factory.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3BsdWdpbi9mYWN0b3J5Lmdv) | `0.00% <0.00%> (-81.49%)` | :arrow_down: |
| [pkg/kubehunter/scanner.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmVodW50ZXIvc2Nhbm5lci5nbw==) | `0.00% <0.00%> (-74.49%)` | :arrow_down: |
| [pkg/kube/runnable\_job.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmUvcnVubmFibGVfam9iLmdv) | `0.00% <0.00%> (-63.73%)` | :arrow_down: |
| [pkg/kubehunter/model.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2t1YmVodW50ZXIvbW9kZWwuZ28=) | `0.00% <0.00%> (-62.86%)` | :arrow_down: |
| [pkg/configauditreport/controller.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NvbmZpZ2F1ZGl0cmVwb3J0L2NvbnRyb2xsZXIuZ28=) | `0.00% <0.00%> (-61.42%)` | :arrow_down: |
| [pkg/vulnerabilityreport/scanner.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL3Z1bG5lcmFiaWxpdHlyZXBvcnQvc2Nhbm5lci5nbw==) | `0.00% <0.00%> (-59.44%)` | :arrow_down: |
| [pkg/configauditreport/scanner.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL2NvbmZpZ2F1ZGl0cmVwb3J0L3NjYW5uZXIuZ28=) | `0.00% <0.00%> (-55.56%)` | :arrow_down: |
| [pkg/operator/controller/vulnerabilityreport.go](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity#diff-cGtnL29wZXJhdG9yL2NvbnRyb2xsZXIvdnVsbmVyYWJpbGl0eXJlcG9ydC5nbw==) | `0.00% <0.00%> (-54.88%)` | :arrow_down: |
| ... and [33 more](https://codecov.io/gh/aquasecurity/starboard/pull/1015/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Last update [e961722...5357c8d](https://codecov.io/gh/aquasecurity/starboard/pull/1015?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=aquasecurity).


Patch:
diff --git a/deploy/crd/clustercompliancedetailreports.crd.yaml b/deploy/crd/clustercompliancedetailreports.crd.yaml
index ec1a96c..df7c4a5 100644
--- a/deploy/crd/clustercompliancedetailreports.crd.yaml
+++ b/deploy/crd/clustercompliancedetailreports.crd.yaml
@@ -13,10 +13,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .report.type.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
diff --git a/deploy/crd/clustercompliancereports.crd.yaml b/deploy/crd/clustercompliancereports.crd.yaml
index 24d3d05..01355b1 100644
--- a/deploy/crd/clustercompliancereports.crd.yaml
+++ b/deploy/crd/clustercompliancereports.crd.yaml
@@ -14,10 +14,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .spec.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
@@ -50,16 +46,12 @@ spec:
             spec:
               type: object
               required:
-                - specKind
                 - name
                 - description
                 - version
                 - cron
                 - controls
               properties:
-                specKind:
-                  type: string
-                  description: 'spedKind define the spec type , example: compliance'
                 name:
                   type: string
                 description:
diff --git a/deploy/specs/nsa-1.0.yaml b/deploy/specs/nsa-1.0.yaml
index 16dcaf8..b4539df 100644
--- a/deploy/specs/nsa-1.0.yaml
+++ b/deploy/specs/nsa-1.0.yaml
@@ -9,7 +9,6 @@ metadata:
     app.kubernetes.io/version: "0.14.1"
     app.kubernetes.io/managed-by: kubectl
 spec:
-  specKind: compliance
   name: nsa
   description: National Security Agency - Kubernetes Hardening Guidance
   version: "1.0"
diff --git a/deploy/static/starboard.yaml b/deploy/static/starboard.yaml
index 25cb783..81109c0 100644
--- a/deploy/static/starboard.yaml
+++ b/deploy/static/starboard.yaml
@@ -421,10 +421,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .spec.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
@@ -457,16 +453,12 @@ spec:
             spec:
               type: object
               required:
-                - specKind
                 - name
                 - description
                 - version
                 - cron
                 - controls
               properties:
-                specKind:
-                  type: string
-                  description: 'spedKind define the spec type , example: compliance'
                 name:
                   type: string
                 description:
@@ -558,10 +550,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .report.type.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
@@ -1992,7 +1980,6 @@ metadata:
     app.kubernetes.io/version: "0.14.1"
     app.kubernetes.io/managed-by: kubectl
 spec:
-  specKind: compliance
   name: nsa
   description: National Security Agency - Kubernetes Hardening Guidance
   version: "1.0"
diff --git a/docs/design/design_compliance_report.md b/docs/design/design_compliance_report.md
index ba8127a..41060a1 100644
--- a/docs/design/design_compliance_report.md
+++ b/docs/design/design_compliance_report.md
@@ -32,7 +32,6 @@ kind: ClusterComplianceReport
 metadata:
   name: nsa
 spec:
-  specKind: compliance
   name: nsa
   description: National Security Agency - Kubernetes Hardening Guidance
   version: "1.0"
@@ -542,10 +541,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .spec.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
@@ -578,16 +573,12 @@ spec:
             spec:
               type: object
               required:
-                - specKind
                 - name
                 - description
                 - version
                 - cron
                 - controls
               properties:
-                specKind:
-                  type: string
-                  description: 'spedKind define the spec type , example: compliance'
                 name:
                   type: string
                 description:
@@ -684,10 +675,6 @@ spec:
       served: true
       storage: true
       additionalPrinterColumns:
-        - jsonPath: .report.type.specKind
-          type: string
-          name: report
-          description: The name of the complience report
         - jsonPath: .metadata.creationTimestamp
           type: date
           name: Age
diff --git a/pkg/apis/aquasecurity/v1alpha1/compliance_types.go b/pkg/apis/aquasecurity/v1alpha1/compliance_types.go
index 9bf4184..f515c2e 100644
--- a/pkg/apis/aquasecurity/v1alpha1/compliance_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/compliance_types.go
@@ -22,7 +22,6 @@ type ClusterComplianceReport struct {
 
 //ReportSpec represent the compliance specification
 type ReportSpec struct {
-	Kind        string    `json:"specKind"`
 	Name        string    `json:"name"`
 	Description string    `json:"description"`
 	Cron        string    `json:"cron"`
diff --git a/pkg/apis/aquasecurity/v1alpha1/compliancedetail_types.go b/pkg/apis/aquasecurity/v1alpha1/compliancedetail_types.go
index 9861878..3d7bf88 100644
--- a/pkg/apis/aquasecurity/v1alpha1/compliancedetail_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/compliancedetail_types.go
@@ -55,8 +55,6 @@ type ScannerCheckResult struct {
 
 // Compliance is the specs for a security assessment report.
 type Compliance struct {
-	// Name the name of the compliance report.
-	Kind string `json:"specKind"`
 	// Name the name of the compliance report.
 	Name string `json:"name"`
 	// Description of the compliance report.
diff --git a/pkg/compliance/io.go b/pkg/compliance/io.go
index 9da19ca..f484aa3 100644
--- a/pkg/compliance/io.go
+++ b/pkg/compliance/io.go
@@ -105,7 +105,10 @@ func (w *cm) createComplianceDetailReport(ctx context.Context, spec v1alpha1.Rep
 		ObjectMeta: metav1.ObjectMeta{
 			Name: name,
 		},
-		Report: v1alpha1.ClusterComplianceDetailReportData{UpdateTimestamp: metav1.NewTime(ext.NewSystemClock().Now()), Summary: summary, Type: v1alpha1.Compliance{Kind: strings.ToLower(spec.Kind), Name: name, Description: strings.ToLower(spec.Description), Version: spec.Version}, ControlChecks: controlChecksDetails},
+		Report: v1alpha1.ClusterComplianceDetailReportData{UpdateTimestamp: metav1.NewTime(ext.NewSystemClock().Now()),
+			Summary:       summary,
+			Type:          v1alpha1.Compliance{Name: name, Description: strings.ToLower(spec.Description), Version: spec.Version},
+			ControlChecks: controlChecksDetails},
 	}
 
 	var existing v1alpha1.ClusterComplianceDetailReport
diff --git a/pkg/operator/controller/ttl_report.go b/pkg/operator/controller/ttl_report.go
index d2493a1..41e1a1c 100644
--- a/pkg/operator/controller/ttl_report.go
+++ b/pkg/operator/controller/ttl_report.go
@@ -5,6 +5,9 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/aquasecurity/starboard/pkg/ext"
+	"github.com/aquasecurity/starboard/pkg/utils"
+
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
 	"github.com/aquasecurity/starboard/pkg/operator/etc"
 	"github.com/aquasecurity/starboard/pkg/operator/predicate"
@@ -20,6 +23,7 @@ type TTLReportReconciler struct {
 	logr.Logger
 	etc.Config
 	client.Client
+	ext.Clock
 }
 
 func (r *TTLReportReconciler) SetupWithManager(mgr ctrl.Manager) error {
@@ -63,11 +67,7 @@ func (r *TTLReportReconciler) reconcileReport() reconcile.Func {
 		if err != nil {
 			return ctrl.Result{}, fmt.Errorf("failed parsing %v with value %v %w", v1alpha1.TTLReportAnnotation, ttlReportAnnotationStr, err)
 		}
-		creationTime := report.Report.UpdateTimestamp
-		ttlExpired, durationToTTLExpiration, err := ttlIsExpired(reportTTLTime, creationTime.Time)
-		if err != nil {
-			return ctrl.Result{}, err
-		}
+		ttlExpired, durationToTTLExpiration := utils.IsTTLExpired(reportTTLTime, report.Report.UpdateTimestamp.Time, r.Clock)
 		if ttlExpired {
 			log.V(1).Info("Removing vulnerabilityReport with expired TTL")
 			err := r.Client.Delete(ctx, report, &client.DeleteOptions{})
@@ -81,16 +81,3 @@ func (r *TTLReportReconciler) reconcileReport() reconcile.Func {
 		return ctrl.Result{RequeueAfter: durationToTTLExpiration}, nil
 	}
 }
-
-func ttlIsExpired(reportTTL time.Duration, creationTime time.Time) (bool, time.Duration, error) {
-	expiresAt := creationTime.Add(reportTTL)
-	currentTime := time.Now()
-	isExpired := currentTime.After(expiresAt)
-
-	if isExpired {
-		return true, time.Duration(0), nil
-	}
-
-	expiresIn := expiresAt.Sub(currentTime)
-	return false, expiresIn, nil
-}
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index f9cbc4e..95a66f9 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -167,6 +167,7 @@ func Start(ctx context.Context, buildInfo starboard.BuildInfo, operatorConfig et
 				Logger: ctrl.Log.WithName("reconciler").WithName("ttlreport"),
 				Config: operatorConfig,
 				Client: mgr.GetClient(),
+				Clock:  ext.NewSystemClock(),
 			}).SetupWithManager(mgr); err != nil {
 				return fmt.Errorf("unable to setup TTLreport reconciler: %w", err)
 			}
diff --git a/pkg/utils/dateutil.go b/pkg/utils/dateutil.go
index 8ca9088..3e87f18 100644
--- a/pkg/utils/dateutil.go
+++ b/pkg/utils/dateutil.go
@@ -26,3 +26,9 @@ func DurationExceeded(duration time.Duration) bool {
 func timeToExpiration(expiresAt time.Time, clock ext.Clock) time.Duration {
 	return expiresAt.Sub(clock.Now())
 }
+
+// IsTTLExpired check whether current time has exceeded creation time + ttl duration
+func IsTTLExpired(ttl time.Duration, creationTime time.Time, clock ext.Clock) (bool, time.Duration) {
+	durationToTTLExpiration := timeToExpiration(creationTime.Add(ttl), clock)
+	return DurationExceeded(durationToTTLExpiration), durationToTTLExpiration
+}


Test patch:
diff --git a/pkg/compliance/testdata/fixture/clusterComplianceDetailReport.json b/pkg/compliance/testdata/fixture/clusterComplianceDetailReport.json
index 34753d3..68e8b81 100644
--- a/pkg/compliance/testdata/fixture/clusterComplianceDetailReport.json
+++ b/pkg/compliance/testdata/fixture/clusterComplianceDetailReport.json
@@ -9,7 +9,6 @@
   "report": {
     "updateTimestamp": "2022-03-09T08:47:03Z",
     "type": {
-      "specKind": "compliance",
       "name": "nsa-details",
       "description": "national security agency - kubernetes hardening guidance",
       "version": "1.0"
diff --git a/pkg/compliance/testdata/fixture/clusterComplianceReport.json b/pkg/compliance/testdata/fixture/clusterComplianceReport.json
index 0314ebb..b309e8e 100644
--- a/pkg/compliance/testdata/fixture/clusterComplianceReport.json
+++ b/pkg/compliance/testdata/fixture/clusterComplianceReport.json
@@ -7,7 +7,6 @@
     "creationTimestamp": null
   },
   "spec": {
-    "specKind": "compliance",
     "name": "nsa",
     "description": "National Security Agency - Kubernetes Hardening Guidance",
     "cron": "* * * * *",
diff --git a/pkg/compliance/testdata/fixture/clusterComplianceSpec.json b/pkg/compliance/testdata/fixture/clusterComplianceSpec.json
index 5c1b676..226520a 100644
--- a/pkg/compliance/testdata/fixture/clusterComplianceSpec.json
+++ b/pkg/compliance/testdata/fixture/clusterComplianceSpec.json
@@ -5,7 +5,6 @@
     "name": "nsa"
   },
   "spec": {
-    "specKind": "compliance",
     "name": "nsa",
     "description": "National Security Agency - Kubernetes Hardening Guidance",
     "version": "1.0",
diff --git a/pkg/compliance/testdata/fixture/nsa-1.0.yaml b/pkg/compliance/testdata/fixture/nsa-1.0.yaml
index 3d3515b..3fff97f 100644
--- a/pkg/compliance/testdata/fixture/nsa-1.0.yaml
+++ b/pkg/compliance/testdata/fixture/nsa-1.0.yaml
@@ -1,5 +1,4 @@
 ---
-specKind: compliance
 name: nsa
 description: National Security Agency - Kubernetes Hardening Guidance
 version: "1.0"
diff --git a/pkg/compliance/testdata/fixture/nsa-1.0_no_controls.yaml b/pkg/compliance/testdata/fixture/nsa-1.0_no_controls.yaml
index 4148072..abd7764 100644
--- a/pkg/compliance/testdata/fixture/nsa-1.0_no_controls.yaml
+++ b/pkg/compliance/testdata/fixture/nsa-1.0_no_controls.yaml
@@ -1,5 +1,4 @@
 ---
-specKind: compliance
 name: nsa
 description: National Security Agency - Kubernetes Hardening Guidance
 version: "1.0"
diff --git a/pkg/operator/controller/ttl_report_test.go b/pkg/operator/controller/ttl_report_test.go
deleted file mode 100644
index 45c4a09..0000000
--- a/pkg/operator/controller/ttl_report_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package controller
-
-import (
-	"testing"
-	"time"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestTTLIsExpired(t *testing.T) {
-	ttlReportAnnotationStr := "10h"
-	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
-	creationTime := time.Now()
-	ttlExpired, _, err := ttlIsExpired(ttlReportTime, creationTime)
-	assert.NoError(t, err)
-	assert.False(t, ttlExpired)
-}
-
-func TestTTLIsNotExpired(t *testing.T) {
-	ttlReportAnnotationStr := "10s"
-	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
-	creationTime := time.Now()
-	then := creationTime.Add(time.Duration(-10) * time.Minute)
-	ttlExpired, durationToTTLExp, err := ttlIsExpired(ttlReportTime, then)
-	t.Logf("Duration to ttl expiration %s, we should rescheduel check", durationToTTLExp)
-	assert.NoError(t, err)
-	assert.True(t, ttlExpired)
-}
diff --git a/pkg/utils/dateutil_test.go b/pkg/utils/dateutil_test.go
index 0bd3c7e..5e19619 100644
--- a/pkg/utils/dateutil_test.go
+++ b/pkg/utils/dateutil_test.go
@@ -59,3 +59,22 @@ func TestDurationExceeded(t *testing.T) {
 		})
 	}
 }
+
+func TestTTLIsNotExpired(t *testing.T) {
+	ttlReportAnnotationStr := "10h"
+	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
+	creationTime := time.Now()
+	ttlExpired, duration := IsTTLExpired(ttlReportTime, creationTime, ext.NewSystemClock())
+	assert.True(t, duration > 0)
+	assert.False(t, ttlExpired)
+}
+
+func TestTTLIsExpired(t *testing.T) {
+	ttlReportAnnotationStr := "10s"
+	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
+	creationTime := time.Now()
+	then := creationTime.Add(time.Duration(-10) * time.Minute)
+	ttlExpired, duration := IsTTLExpired(ttlReportTime, then, ext.NewSystemClock())
+	assert.True(t, duration <= 0)
+	assert.True(t, ttlExpired)
+}