Skip to content

Commit fe008aa

Browse files
author
Niklas Burchhardt
committed
test(resolver): add missing test cases for idempotency, TTL, and auth selection
Added scenarios for: - Idempotency and record appending during challenges - Proper propagation of TTL configuration - Service Account vs. Auth Token authentication selection - Failure handling during RRSet creation and updates - Robustness against empty record sets
1 parent 75d1b14 commit fe008aa

File tree

1 file changed

+335
-1
lines changed

1 file changed

+335
-1
lines changed

internal/resolver/resolver_test.go

Lines changed: 335 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

235548
type cleanSuite struct {
@@ -344,3 +657,24 @@ func (s *cleanSuite) TestSuccessDeleteRRSet() {
344657
func 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

Comments
 (0)