@@ -21,6 +21,7 @@ package accessmonitoring
2121import (
2222 "context"
2323 "testing"
24+ "time"
2425
2526 "github.com/stretchr/testify/mock"
2627 "github.com/stretchr/testify/require"
@@ -52,7 +53,7 @@ func mockFetchRecipient(ctx context.Context, recipient string) (*common.Recipien
5253 return nil , nil
5354}
5455
55- func TestRecipeints (t * testing.T ) {
56+ func TestRecipients (t * testing.T ) {
5657 const (
5758 pluginName = "fakePluginName"
5859 pluginType = "fakePluginType"
@@ -133,7 +134,7 @@ func TestRecipeints(t *testing.T) {
133134 require .ElementsMatch (t , []string {}, rawRecipients )
134135}
135136
136- func TestRecipeintsWithResources (t * testing.T ) {
137+ func TestRecipientsWithResources (t * testing.T ) {
137138 const (
138139 pluginName = "fakePluginName"
139140 pluginType = "fakePluginType"
@@ -205,6 +206,85 @@ func TestRecipeintsWithResources(t *testing.T) {
205206 require .ElementsMatch (t , []string {recipient }, rawRecipients )
206207}
207208
209+ func TestRecipientsWithSchedules (t * testing.T ) {
210+ const (
211+ pluginName = "fakePluginName"
212+ pluginType = "fakePluginType"
213+ 214+ )
215+
216+ teleportClient := & mockTeleportClient {}
217+ teleportClient .
218+ On ("GetUser" , mock .Anything , mock .Anything , mock .Anything ).
219+ Return (& types.UserV2 {}, nil )
220+
221+ amrh := NewRuleHandler (RuleHandlerConfig {
222+ Client : teleportClient ,
223+ PluginType : pluginType ,
224+ PluginName : pluginName ,
225+ FetchRecipientCallback : func (ctx context.Context , recipient string ) (* common.Recipient , error ) {
226+ return emailRecipient (recipient ), nil
227+ },
228+ })
229+
230+ rule1 , err := services .NewAccessMonitoringRuleWithLabels ("rule1" , nil , & pb.AccessMonitoringRuleSpec {
231+ Subjects : []string {types .KindAccessRequest },
232+ Schedules : map [string ]* pb.Schedule {
233+ "default" : {
234+ Time : & pb.TimeSchedule {
235+ Shifts : []* pb.TimeSchedule_Shift {
236+ {
237+ Weekday : time .Monday .String (),
238+ Start : "14:00" ,
239+ End : "15:00" ,
240+ },
241+ },
242+ },
243+ },
244+ },
245+ Condition : `true` ,
246+ Notification : & pb.Notification {
247+ Name : pluginName ,
248+ Recipients : []string {recipient },
249+ },
250+ })
251+ require .NoError (t , err )
252+ err = amrh .HandleAccessMonitoringRule (context .Background (), types.Event {
253+ Type : types .OpPut ,
254+ Resource : types .Resource153ToLegacy (rule1 ),
255+ })
256+ require .NoError (t , err )
257+ require .Len (t , amrh .getAccessMonitoringRules (), 1 )
258+
259+ ctx := context .Background ()
260+
261+ // Expect recipient from matching rule.
262+ req := & types.AccessRequestV3 {
263+ Spec : types.AccessRequestSpecV3 {
264+ Created : time .Date (2025 , time .August , 11 , 14 , 30 , 0 , 0 , time .UTC ),
265+ },
266+ }
267+
268+ recipients := amrh .RecipientsFromAccessMonitoringRules (ctx , req )
269+ require .ElementsMatch (t , []common.Recipient {* emailRecipient (recipient )}, recipients .ToSlice ())
270+
271+ rawRecipients := amrh .RawRecipientsFromAccessMonitoringRules (ctx , req )
272+ require .ElementsMatch (t , []string {recipient }, rawRecipients )
273+
274+ // Expect no recipient when not in schedule.
275+ req = & types.AccessRequestV3 {
276+ Spec : types.AccessRequestSpecV3 {
277+ Created : time .Date (2025 , time .August , 11 , 15 , 30 , 0 , 0 , time .UTC ),
278+ },
279+ }
280+
281+ recipients = amrh .RecipientsFromAccessMonitoringRules (ctx , req )
282+ require .ElementsMatch (t , []common.Recipient {}, recipients .ToSlice ())
283+
284+ rawRecipients = amrh .RawRecipientsFromAccessMonitoringRules (ctx , req )
285+ require .ElementsMatch (t , []string {}, rawRecipients )
286+ }
287+
208288func emailRecipient (recipient string ) * common.Recipient {
209289 return & common.Recipient {
210290 Name : recipient ,
0 commit comments