bluegreen_reconciler_test.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package controllers
  2. import (
  3. "fmt"
  4. "reflect"
  5. "testing"
  6. "github.com/golang/mock/gomock"
  7. appv1 "github.com/kakao/bluegreen/api/v1"
  8. "github.com/kakao/bluegreen/controllers/bluegreen"
  9. "github.com/stretchr/testify/assert"
  10. v1 "k8s.io/api/core/v1"
  11. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  12. "k8s.io/apimachinery/pkg/runtime"
  13. "k8s.io/apimachinery/pkg/types"
  14. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  15. clientgoscheme "k8s.io/client-go/kubernetes/scheme"
  16. "sigs.k8s.io/controller-runtime/pkg/reconcile"
  17. )
  18. var (
  19. testScheme = runtime.NewScheme()
  20. )
  21. func init() {
  22. utilruntime.Must(clientgoscheme.AddToScheme(testScheme))
  23. utilruntime.Must(appv1.AddToScheme(testScheme))
  24. }
  25. func TestBlueGreenResconciler(t *testing.T) {
  26. ctrl := gomock.NewController(t)
  27. defer ctrl.Finish()
  28. c := bluegreen.NewMockClient(ctrl)
  29. r := &BlueGreenReconciler{
  30. Client: c,
  31. Scheme: testScheme,
  32. }
  33. req := reconcile.Request{NamespacedName: types.NamespacedName{
  34. Namespace: "test",
  35. Name: "bluegreen",
  36. }}
  37. bg := appv1.BlueGreen{
  38. ObjectMeta: metav1.ObjectMeta{
  39. Namespace: req.Namespace,
  40. Name: req.Name,
  41. },
  42. Spec: appv1.BlueGreenSpec{
  43. RouteTo: appv1.Blue,
  44. BlueSpec: &v1.PodSpec{
  45. Containers: []v1.Container{{Name: "test"}},
  46. },
  47. GreenSpec: nil,
  48. },
  49. }
  50. blugreenMatcher := &GenericMatcher[*appv1.BlueGreen]{func(in *appv1.BlueGreen) bool { return reflect.DeepEqual(bg, *in) }}
  51. // EXPECTING
  52. c.EXPECT().Get(gomock.Any(), gomock.Eq(req.NamespacedName), gomock.Any()).
  53. SetArg(2, bg).
  54. Return(nil)
  55. c.EXPECT().CreateOrUpdateService(gomock.Any(), blugreenMatcher).
  56. Return(nil)
  57. c.EXPECT().CreateOrUpdateDeployment(gomock.Any(), blugreenMatcher, gomock.Eq(appv1.Blue), gomock.Eq(*bg.Spec.BlueSpec)).
  58. Return(nil)
  59. c.EXPECT().UpdateStatus(gomock.Any(),
  60. &GenericMatcher[*appv1.BlueGreen]{func(bg *appv1.BlueGreen) bool { return *bg.Status.RouteTo == appv1.Blue }},
  61. ).Return(nil)
  62. // Reconciling
  63. result, err := r.Reconcile(ctx, req)
  64. // Validation
  65. assert.NoError(t, err)
  66. assert.Equal(t, reconcile.Result{Requeue: false}, result)
  67. }
  68. var _ gomock.Matcher = &GenericMatcher[interface{}]{}
  69. type GenericMatcher[T interface{}] struct {
  70. F func(T) bool
  71. }
  72. func (m *GenericMatcher[T]) Matches(x interface{}) bool {
  73. if v, ok := x.(T); ok {
  74. return m.F(v)
  75. } else {
  76. return false
  77. }
  78. }
  79. func (m *GenericMatcher[T]) String() string {
  80. return fmt.Sprintf("matching %v", reflect.TypeOf(new(T)))
  81. }
  82. var _ gomock.Matcher = &RuntimeObjectMatcher{}
  83. type RuntimeObjectMatcher struct {
  84. object runtime.Object
  85. }
  86. // Matches implements gomock.Matcher
  87. func (r *RuntimeObjectMatcher) Matches(x interface{}) bool {
  88. return reflect.DeepEqual(r.object, x)
  89. }
  90. // String implements gomock.Matcher
  91. func (r *RuntimeObjectMatcher) String() string {
  92. gok := r.object.GetObjectKind().GroupVersionKind()
  93. return fmt.Sprintf("should match %s/%s/%s", gok.Group, gok.Version, gok.Kind)
  94. }