github.com/kotalco/kotal@v0.3.0/controllers/bitcoin/node_controller_test.go (about)

     1  package controllers
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"time"
     8  
     9  	bitcoinv1alpha1 "github.com/kotalco/kotal/apis/bitcoin/v1alpha1"
    10  	bitcoinClients "github.com/kotalco/kotal/clients/bitcoin"
    11  	"github.com/kotalco/kotal/controllers/shared"
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	"github.com/onsi/gomega/gstruct"
    15  	appsv1 "k8s.io/api/apps/v1"
    16  	corev1 "k8s.io/api/core/v1"
    17  	"k8s.io/apimachinery/pkg/api/resource"
    18  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    19  	"k8s.io/apimachinery/pkg/types"
    20  	"k8s.io/apimachinery/pkg/util/intstr"
    21  )
    22  
    23  var _ = Describe("Bitcoin node controller", func() {
    24  	ns := &corev1.Namespace{
    25  		ObjectMeta: metav1.ObjectMeta{
    26  			Name: "bitcoin",
    27  		},
    28  	}
    29  
    30  	key := types.NamespacedName{
    31  		Name:      "bitcoin-node",
    32  		Namespace: ns.Name,
    33  	}
    34  
    35  	testImage := "kotalco/bitcoin-core:controller-test"
    36  
    37  	spec := bitcoinv1alpha1.NodeSpec{
    38  		Image:   testImage,
    39  		Network: bitcoinv1alpha1.Mainnet,
    40  		RPC:     true,
    41  	}
    42  
    43  	toCreate := &bitcoinv1alpha1.Node{
    44  		ObjectMeta: metav1.ObjectMeta{
    45  			Name:      key.Name,
    46  			Namespace: key.Namespace,
    47  		},
    48  		Spec: spec,
    49  	}
    50  
    51  	client := bitcoinClients.NewClient(toCreate, nil)
    52  
    53  	t := true
    54  
    55  	nodeOwnerReference := metav1.OwnerReference{
    56  		APIVersion:         "bitcoin.kotal.io/v1alpha1",
    57  		Kind:               "Node",
    58  		Name:               toCreate.Name,
    59  		Controller:         &t,
    60  		BlockOwnerDeletion: &t,
    61  	}
    62  
    63  	It(fmt.Sprintf("Should create %s namespace", ns.Name), func() {
    64  		Expect(k8sClient.Create(context.TODO(), ns)).To(Succeed())
    65  	})
    66  
    67  	It("should create Bitcoin node", func() {
    68  		if os.Getenv(shared.EnvUseExistingCluster) != "true" {
    69  			toCreate.Default()
    70  		}
    71  		Expect(k8sClient.Create(context.Background(), toCreate)).Should(Succeed())
    72  	})
    73  
    74  	It("Should get Bitcoin node", func() {
    75  		fetched := &bitcoinv1alpha1.Node{}
    76  		Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
    77  		Expect(fetched.Spec).To(Equal(toCreate.Spec))
    78  		nodeOwnerReference.UID = fetched.UID
    79  		time.Sleep(5 * time.Second)
    80  	})
    81  
    82  	It("Should create node statefulset", func() {
    83  		fetched := &appsv1.StatefulSet{}
    84  		Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
    85  		Expect(fetched.OwnerReferences).To(ContainElements(nodeOwnerReference))
    86  		Expect(*fetched.Spec.Template.Spec.SecurityContext).To(gstruct.MatchFields(gstruct.IgnoreExtras, gstruct.Fields{
    87  			"RunAsUser":    gstruct.PointTo(Equal(int64(1000))),
    88  			"RunAsGroup":   gstruct.PointTo(Equal(int64(3000))),
    89  			"FSGroup":      gstruct.PointTo(Equal(int64(2000))),
    90  			"RunAsNonRoot": gstruct.PointTo(Equal(true)),
    91  		}))
    92  		Expect(fetched.Spec.Template.Spec.Containers[0].Name).To(Equal("node"))
    93  		Expect(fetched.Spec.Template.Spec.Containers[0].Image).To(Equal(testImage))
    94  		Expect(fetched.Spec.Template.Spec.Containers[0].Env).To(Equal(client.Env()))
    95  		Expect(fetched.Spec.Template.Spec.Containers[0].Command).To(Equal(client.Command()))
    96  		Expect(fetched.Spec.Template.Spec.Containers[0].Args).To(Equal(client.Args()))
    97  		Expect(fetched.Spec.Template.Spec.Containers[0].VolumeMounts).To(ContainElements(
    98  			corev1.VolumeMount{
    99  				Name:      "data",
   100  				MountPath: shared.PathData(client.HomeDir()),
   101  			},
   102  		))
   103  		// volumes
   104  		Expect(fetched.Spec.Template.Spec.Volumes).To(ContainElements(
   105  			[]corev1.Volume{
   106  				{
   107  					Name: "data",
   108  					VolumeSource: corev1.VolumeSource{
   109  						PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
   110  							ClaimName: toCreate.Name,
   111  						},
   112  					},
   113  				},
   114  			},
   115  		))
   116  	})
   117  
   118  	It("Should create allocate correct resources to node statefulset", func() {
   119  		fetched := &appsv1.StatefulSet{}
   120  		expectedResources := corev1.ResourceRequirements{
   121  			Requests: corev1.ResourceList{
   122  				corev1.ResourceCPU:    resource.MustParse(bitcoinv1alpha1.DefaultNodeCPURequest),
   123  				corev1.ResourceMemory: resource.MustParse(bitcoinv1alpha1.DefaultNodeMemoryRequest),
   124  			},
   125  			Limits: corev1.ResourceList{
   126  				corev1.ResourceCPU:    resource.MustParse(bitcoinv1alpha1.DefaultNodeCPULimit),
   127  				corev1.ResourceMemory: resource.MustParse(bitcoinv1alpha1.DefaultNodeMemoryLimit),
   128  			},
   129  		}
   130  		Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
   131  		Expect(fetched.Spec.Template.Spec.Containers[0].Resources).To(Equal(expectedResources))
   132  	})
   133  
   134  	It("Should create node data persistent volume with correct resources", func() {
   135  		fetched := &corev1.PersistentVolumeClaim{}
   136  		Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
   137  		Expect(fetched.OwnerReferences).To(ContainElements(nodeOwnerReference))
   138  		expectedResources := corev1.VolumeResourceRequirements{
   139  			Requests: corev1.ResourceList{
   140  				corev1.ResourceStorage: resource.MustParse(bitcoinv1alpha1.DefaultNodeStorageRequest),
   141  			},
   142  		}
   143  		Expect(fetched.Spec.Resources).To(Equal(expectedResources))
   144  	})
   145  
   146  	It("Should create node service", func() {
   147  		fetched := &corev1.Service{}
   148  		Expect(k8sClient.Get(context.Background(), key, fetched)).To(Succeed())
   149  		Expect(fetched.OwnerReferences).To(ContainElements(nodeOwnerReference))
   150  		Expect(fetched.Spec.Ports).To(ContainElements(
   151  			[]corev1.ServicePort{
   152  				{
   153  					Name:       "p2p",
   154  					Port:       int32(bitcoinv1alpha1.DefaultMainnetP2PPort),
   155  					TargetPort: intstr.FromString("p2p"),
   156  					Protocol:   corev1.ProtocolTCP,
   157  				},
   158  				{
   159  					Name:       "rpc",
   160  					Port:       int32(bitcoinv1alpha1.DefaultMainnetRPCPort),
   161  					TargetPort: intstr.FromString("rpc"),
   162  					Protocol:   corev1.ProtocolTCP,
   163  				},
   164  			},
   165  		))
   166  	})
   167  
   168  	It(fmt.Sprintf("Should delete %s namespace", ns.Name), func() {
   169  		Expect(k8sClient.Delete(context.Background(), ns)).To(Succeed())
   170  	})
   171  
   172  })