@@ -223,13 +223,326 @@ func (s *presentSuite) TestSuccessUpdateRRSet() {
223223 Return (s .mockRRSetRepository , nil )
224224 s .mockRRSetRepository .EXPECT ().
225225 FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
226- Return (& stackitdnsclient_new.RecordSet {}, nil )
226+ Return (& stackitdnsclient_new.RecordSet {
227+ Records : & []stackitdnsclient_new.Record {},
228+ }, nil )
229+ s .mockRRSetRepository .EXPECT ().
230+ UpdateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
231+ return rrSet .Records != nil && len (* rrSet .Records ) == 1
232+ })).
233+ Return (nil )
234+
235+ err := s .resolver .Present (challengeRequest )
236+ s .NoError (err )
237+ }
238+
239+ func (s * presentSuite ) TestSuccessPresentIdempotent () {
240+ s .mockConfigProvider .EXPECT ().
241+ LoadConfig (gomock .Any ()).
242+ Return (resolver.StackitDnsProviderConfig {}, nil )
243+ s .mockSecretFetcher .EXPECT ().
244+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
245+ Return ("" , nil )
246+ s .mockZoneRepositoryFactory .EXPECT ().
247+ NewZoneRepository (gomock .Any ()).
248+ Return (s .mockZoneRepository , nil )
249+ s .mockZoneRepository .EXPECT ().
250+ FetchZone (gomock .Any (), gomock .Any ()).
251+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
252+ s .mockRRSetRepositoryFactory .EXPECT ().
253+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
254+ Return (s .mockRRSetRepository , nil )
255+
256+ challengeKey := "challenge-key"
257+ req := & v1alpha1.ChallengeRequest {
258+ Config : configJson ,
259+ Key : challengeKey ,
260+ }
261+
262+ s .mockRRSetRepository .EXPECT ().
263+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
264+ Return (& stackitdnsclient_new.RecordSet {
265+ Records : & []stackitdnsclient_new.Record {
266+ {Content : & challengeKey },
267+ },
268+ }, nil )
269+
270+ s .mockRRSetRepository .EXPECT ().
271+ UpdateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
272+ return len (* rrSet .Records ) == 1 && * (* rrSet .Records )[0 ].Content == challengeKey
273+ })).
274+ Return (nil )
275+
276+ err := s .resolver .Present (req )
277+ s .NoError (err )
278+ }
279+
280+ //nolint:gocognit // this is a test
281+ func (s * presentSuite ) TestSuccessPresentAppended () {
282+ s .mockConfigProvider .EXPECT ().
283+ LoadConfig (gomock .Any ()).
284+ Return (resolver.StackitDnsProviderConfig {}, nil )
285+ s .mockSecretFetcher .EXPECT ().
286+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
287+ Return ("" , nil )
288+ s .mockZoneRepositoryFactory .EXPECT ().
289+ NewZoneRepository (gomock .Any ()).
290+ Return (s .mockZoneRepository , nil )
291+ s .mockZoneRepository .EXPECT ().
292+ FetchZone (gomock .Any (), gomock .Any ()).
293+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
294+ s .mockRRSetRepositoryFactory .EXPECT ().
295+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
296+ Return (s .mockRRSetRepository , nil )
297+
298+ existingKey := "existing-key"
299+ newKey := "new-key"
300+ req := & v1alpha1.ChallengeRequest {
301+ Config : configJson ,
302+ Key : newKey ,
303+ }
304+
305+ s .mockRRSetRepository .EXPECT ().
306+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
307+ Return (& stackitdnsclient_new.RecordSet {
308+ Records : & []stackitdnsclient_new.Record {
309+ {Content : & existingKey },
310+ },
311+ }, nil )
312+
313+ s .mockRRSetRepository .EXPECT ().
314+ UpdateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
315+ if rrSet .Records == nil || len (* rrSet .Records ) != 2 {
316+ return false
317+ }
318+ foundExisting := false
319+ foundNew := false
320+ for _ , r := range * rrSet .Records {
321+ if r .Content != nil && * r .Content == existingKey {
322+ foundExisting = true
323+ }
324+ if r .Content != nil && * r .Content == newKey {
325+ foundNew = true
326+ }
327+ }
328+
329+ return foundExisting && foundNew
330+ })).
331+ Return (nil )
332+
333+ err := s .resolver .Present (req )
334+ s .NoError (err )
335+ }
336+
337+ func (s * presentSuite ) TestPresentRRSetWithEmptyRecords () {
338+ s .mockConfigProvider .EXPECT ().
339+ LoadConfig (gomock .Any ()).
340+ Return (resolver.StackitDnsProviderConfig {}, nil )
341+ s .mockSecretFetcher .EXPECT ().
342+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
343+ Return ("" , nil )
344+ s .mockZoneRepositoryFactory .EXPECT ().
345+ NewZoneRepository (gomock .Any ()).
346+ Return (s .mockZoneRepository , nil )
347+ s .mockZoneRepository .EXPECT ().
348+ FetchZone (gomock .Any (), gomock .Any ()).
349+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
350+ s .mockRRSetRepositoryFactory .EXPECT ().
351+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
352+ Return (s .mockRRSetRepository , nil )
353+
354+ s .mockRRSetRepository .EXPECT ().
355+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
356+ Return (& stackitdnsclient_new.RecordSet {
357+ Records : & []stackitdnsclient_new.Record {},
358+ }, nil )
359+ s .mockRRSetRepository .EXPECT ().
360+ UpdateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
361+ return len (* rrSet .Records ) == 1
362+ })).Return (nil )
363+ err := s .resolver .Present (challengeRequest )
364+ s .NoError (err )
365+ }
366+
367+ func (s * presentSuite ) TestFailCreateRRSet () {
368+ s .mockConfigProvider .EXPECT ().
369+ LoadConfig (gomock .Any ()).
370+ Return (resolver.StackitDnsProviderConfig {}, nil )
371+ s .mockSecretFetcher .EXPECT ().
372+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
373+ Return ("" , nil )
374+ s .mockZoneRepositoryFactory .EXPECT ().
375+ NewZoneRepository (gomock .Any ()).
376+ Return (s .mockZoneRepository , nil )
377+ s .mockZoneRepository .EXPECT ().
378+ FetchZone (gomock .Any (), gomock .Any ()).
379+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
380+ s .mockRRSetRepositoryFactory .EXPECT ().
381+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
382+ Return (s .mockRRSetRepository , nil )
383+ s .mockRRSetRepository .EXPECT ().
384+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
385+ Return (nil , repository .ErrRRSetNotFound )
386+ s .mockRRSetRepository .EXPECT ().
387+ CreateRRSet (gomock .Any (), gomock .Any ()).
388+ Return (fmt .Errorf ("error creating rr set" ))
389+
390+ err := s .resolver .Present (challengeRequest )
391+ s .Error (err )
392+ s .Contains (err .Error (), "error creating rr set" )
393+ }
394+
395+ func (s * presentSuite ) TestFailUpdateRRSet () {
396+ s .mockConfigProvider .EXPECT ().
397+ LoadConfig (gomock .Any ()).
398+ Return (resolver.StackitDnsProviderConfig {}, nil )
399+ s .mockSecretFetcher .EXPECT ().
400+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
401+ Return ("" , nil )
402+ s .mockZoneRepositoryFactory .EXPECT ().
403+ NewZoneRepository (gomock .Any ()).
404+ Return (s .mockZoneRepository , nil )
405+ s .mockZoneRepository .EXPECT ().
406+ FetchZone (gomock .Any (), gomock .Any ()).
407+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
408+ s .mockRRSetRepositoryFactory .EXPECT ().
409+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
410+ Return (s .mockRRSetRepository , nil )
411+ s .mockRRSetRepository .EXPECT ().
412+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
413+ Return (& stackitdnsclient_new.RecordSet {
414+ Records : & []stackitdnsclient_new.Record {},
415+ }, nil )
227416 s .mockRRSetRepository .EXPECT ().
228417 UpdateRRSet (gomock .Any (), gomock .Any ()).
418+ Return (fmt .Errorf ("error updating rr set" ))
419+
420+ err := s .resolver .Present (challengeRequest )
421+ s .Error (err )
422+ s .Contains (err .Error (), "error updating rr set" )
423+ }
424+
425+ func (s * presentSuite ) TestTTLPropagation () {
426+ ttl := int64 (600 )
427+ // Test Create
428+ s .mockConfigProvider .EXPECT ().
429+ LoadConfig (gomock .Any ()).
430+ Return (resolver.StackitDnsProviderConfig {AcmeTxtRecordTTL : ttl }, nil )
431+ s .mockSecretFetcher .EXPECT ().
432+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
433+ Return ("" , nil ).AnyTimes ()
434+ s .mockZoneRepositoryFactory .EXPECT ().
435+ NewZoneRepository (gomock .Any ()).
436+ Return (s .mockZoneRepository , nil )
437+ s .mockZoneRepository .EXPECT ().
438+ FetchZone (gomock .Any (), gomock .Any ()).
439+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
440+ s .mockRRSetRepositoryFactory .EXPECT ().
441+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
442+ Return (s .mockRRSetRepository , nil )
443+
444+ s .mockRRSetRepository .EXPECT ().
445+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
446+ Return (nil , repository .ErrRRSetNotFound )
447+ s .mockRRSetRepository .EXPECT ().
448+ CreateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
449+ return * rrSet .Ttl == ttl
450+ })).
229451 Return (nil )
230452
231453 err := s .resolver .Present (challengeRequest )
232454 s .NoError (err )
455+
456+ // Test Update
457+ s .mockConfigProvider .EXPECT ().
458+ LoadConfig (gomock .Any ()).
459+ Return (resolver.StackitDnsProviderConfig {AcmeTxtRecordTTL : ttl }, nil )
460+ s .mockZoneRepositoryFactory .EXPECT ().
461+ NewZoneRepository (gomock .Any ()).
462+ Return (s .mockZoneRepository , nil )
463+ s .mockZoneRepository .EXPECT ().
464+ FetchZone (gomock .Any (), gomock .Any ()).
465+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
466+ s .mockRRSetRepositoryFactory .EXPECT ().
467+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
468+ Return (s .mockRRSetRepository , nil )
469+
470+ s .mockRRSetRepository .EXPECT ().
471+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
472+ Return (& stackitdnsclient_new.RecordSet {
473+ Records : & []stackitdnsclient_new.Record {},
474+ }, nil )
475+ s .mockRRSetRepository .EXPECT ().
476+ UpdateRRSet (gomock .Any (), matchedBy (func (rrSet stackitdnsclient_new.RecordSet ) bool {
477+ return * rrSet .Ttl == ttl
478+ })).
479+ Return (nil )
480+
481+ err = s .resolver .Present (challengeRequest )
482+ s .NoError (err )
483+ }
484+
485+ func (s * presentSuite ) TestAuthMethodSelection () {
486+ // Test Service Account
487+ s .Run ("Service Account" , func () {
488+ s .mockConfigProvider .EXPECT ().
489+ LoadConfig (gomock .Any ()).
490+ Return (resolver.StackitDnsProviderConfig {
491+ ServiceAccountKeyPath : "/path/to/key" ,
492+ }, nil )
493+ s .mockZoneRepositoryFactory .EXPECT ().
494+ NewZoneRepository (matchedBy (func (cfg repository.Config ) bool {
495+ return cfg .UseSaKey && cfg .SaKeyPath == "/path/to/key"
496+ })).
497+ Return (s .mockZoneRepository , nil )
498+ s .mockZoneRepository .EXPECT ().
499+ FetchZone (gomock .Any (), gomock .Any ()).
500+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
501+ s .mockRRSetRepositoryFactory .EXPECT ().
502+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
503+ Return (s .mockRRSetRepository , nil )
504+ s .mockRRSetRepository .EXPECT ().
505+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
506+ Return (nil , repository .ErrRRSetNotFound )
507+ s .mockRRSetRepository .EXPECT ().
508+ CreateRRSet (gomock .Any (), gomock .Any ()).
509+ Return (nil )
510+
511+ err := s .resolver .Present (challengeRequest )
512+ s .NoError (err )
513+ })
514+
515+ // Test Auth Token
516+ s .Run ("Auth Token" , func () {
517+ s .mockConfigProvider .EXPECT ().
518+ LoadConfig (gomock .Any ()).
519+ Return (resolver.StackitDnsProviderConfig {
520+ AuthTokenSecretRef : "secret" ,
521+ }, nil )
522+ s .mockSecretFetcher .EXPECT ().
523+ StringFromSecret (gomock .Any (), gomock .Any (), gomock .Any ()).
524+ Return ("token123" , nil )
525+ s .mockZoneRepositoryFactory .EXPECT ().
526+ NewZoneRepository (matchedBy (func (cfg repository.Config ) bool {
527+ return ! cfg .UseSaKey && cfg .AuthToken == "token123"
528+ })).
529+ Return (s .mockZoneRepository , nil )
530+ s .mockZoneRepository .EXPECT ().
531+ FetchZone (gomock .Any (), gomock .Any ()).
532+ Return (& stackitdnsclient_new.Zone {Id : toPtr ("test" )}, nil )
533+ s .mockRRSetRepositoryFactory .EXPECT ().
534+ NewRRSetRepository (gomock .Any (), gomock .Any ()).
535+ Return (s .mockRRSetRepository , nil )
536+ s .mockRRSetRepository .EXPECT ().
537+ FetchRRSetForZone (gomock .Any (), gomock .Any (), gomock .Any ()).
538+ Return (nil , repository .ErrRRSetNotFound )
539+ s .mockRRSetRepository .EXPECT ().
540+ CreateRRSet (gomock .Any (), gomock .Any ()).
541+ Return (nil )
542+
543+ err := s .resolver .Present (challengeRequest )
544+ s .NoError (err )
545+ })
233546}
234547
235548type cleanSuite struct {
@@ -344,3 +657,24 @@ func (s *cleanSuite) TestSuccessDeleteRRSet() {
344657func toPtr (str string ) * string {
345658 return & str
346659}
660+
661+ func matchedBy [T any ](fn func (T ) bool ) gomock.Matcher {
662+ return matcher [T ]{fn }
663+ }
664+
665+ type matcher [T any ] struct {
666+ fn func (T ) bool
667+ }
668+
669+ func (m matcher [T ]) Matches (x interface {}) bool {
670+ v , ok := x .(T )
671+ if ! ok {
672+ return false
673+ }
674+
675+ return m .fn (v )
676+ }
677+
678+ func (m matcher [T ]) String () string {
679+ return "custom matcher"
680+ }
0 commit comments