From c59afa752d9746af6d870635ce3baaaff67b8027 Mon Sep 17 00:00:00 2001
From: John Olheiser <john.olheiser@gmail.com>
Date: Mon, 18 Oct 2021 15:12:26 -0500
Subject: [PATCH] Allow mocking timeutil (#17354)

Signed-off-by: jolheiser <john.olheiser@gmail.com>
---
 models/user_heatmap_test.go   |  6 ++++++
 modules/timeutil/timestamp.go | 16 ++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go
index c40e341593..8d2002b1a0 100644
--- a/models/user_heatmap_test.go
+++ b/models/user_heatmap_test.go
@@ -7,9 +7,11 @@ package models
 import (
 	"fmt"
 	"testing"
+	"time"
 
 	"code.gitea.io/gitea/models/db"
 	"code.gitea.io/gitea/modules/json"
+	"code.gitea.io/gitea/modules/timeutil"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -39,6 +41,10 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
 	// Prepare
 	assert.NoError(t, db.PrepareTestDatabase())
 
+	// Mock time
+	timeutil.Set(time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC))
+	defer timeutil.Unset()
+
 	for i, tc := range testCases {
 		user := db.AssertExistsAndLoadBean(t, &User{ID: tc.userID}).(*User)
 
diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go
index b1c60c3084..1fe8d4fcb1 100644
--- a/modules/timeutil/timestamp.go
+++ b/modules/timeutil/timestamp.go
@@ -13,8 +13,24 @@ import (
 // TimeStamp defines a timestamp
 type TimeStamp int64
 
+// mock is NOT concurrency-safe!!
+var mock time.Time
+
+// Set sets the time to a mocked time.Time
+func Set(now time.Time) {
+	mock = now
+}
+
+// Unset will unset the mocked time.Time
+func Unset() {
+	mock = time.Time{}
+}
+
 // TimeStampNow returns now int64
 func TimeStampNow() TimeStamp {
+	if !mock.IsZero() {
+		return TimeStamp(mock.Unix())
+	}
 	return TimeStamp(time.Now().Unix())
 }