Search code examples
fabric8

Fabric8 customResourceDefinitions test


I am working on Fabric8 unit test, now I am trying to create a CRD against KubernetesServer.

import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;

public class TestCertManagerService {

  @Rule
  public KubernetesServer server = new KubernetesServer();


  @Test
  @DisplayName("Should list all CronTab custom resources")
  public void testCronTabCrd() throws IOException {
    // Given
    //server.expect().get().withPath("/apis/stable.example.com/v1/namespaces/default/crontabs").andReturn(HttpURLConnection.HTTP_OK, ?????).once();
    KubernetesClient client = server.getClient();


    CustomResourceDefinition cronTabCrd = client.apiextensions().v1().customResourceDefinitions()
        .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yml")))
        .get();
    client.apiextensions().v1().customResourceDefinitions().create(cronTabCrd);

  }
}

When I ran it, I got the following error

TestCertManagerService > testCronTabCrd FAILED
    io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://localhost:60690/apis/apiextensions.k8s.io/v1/customresourcedefinitions.
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure(OperationSupport.java:694)
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure(OperationSupport.java:673)
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.assertResponseCode(OperationSupport.java:626)
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:566)
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:527)
        at app//io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:510)
        at app//io.fabric8.kubernetes.client.dsl.base.BaseOperation.listRequestHelper(BaseOperation.java:136)
        at app//io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:505)
        at app//io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:494)
        at app//io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:87)
        at app//com.ibm.si.qradar.cp4s.service.certmanager.TestCertManagerService.testCronTabCrd(TestCertManagerService.java:94)

I have a few of questions: (1) In this case, I am using v1() interface, sometimes I saw example code is using v1beta1(), what decides this version? By the way, I am using Kubernetes-client library 5.9.0

(2) In my code , I comments out this line

server.expect().get().withPath("/apis/stable.example.com/v1/namespaces/default/crontabs").andReturn(HttpURLConnection.HTTP_OK, ?????).once();

What is this statement for? In my case, I want to load a CRD, then create a CR, what is "?????" in the statement?

  1. Any ideas for stack trace? How to fix it?

I appreciate it in advance.


Solution

  • From the code which you shared, it looks like you're using Fabric8 Kubernetes Mock Server in expectations mode. Expectations mode requires the user to set the REST API expectations. So the code shown below is setting some expectations from Mock Server viewpoint.

    // Given
    server.expect().get()
          .withPath("/apis/stable.example.com/v1/namespaces/default/crontabs")
          .andReturn(HttpURLConnection.HTTP_OK, getCronTabList())
          .once();
    

    These are the expectations set:

    1. Mock Server would be requested a GET request at this URL: /apis/stable.example.com/v1/namespaces/default/crontabs . From URL we can expect a resource under stable.example.com apigroup with v1 version, default namespace and crontabs as plural.
    2. When this URL is being hit, you're also defining response code and response body in andReturn() method. First argument is the response code (200 in this case) and second argument is the response body (a List object of CronTab which would be serialized and sent as response by mock server).
    3. This request is only hit .once(), if KubernetesClient created by Mock Server requests this endpoint more than once; the test would fail. If you want to hit the endpoint more than once, you can use .times(..) method instead.

    But in your test I see you're loading a CustomResourceDefinition from YAML and creating it which doesn't seem to match the expectations you set earlier. If you're writing a test about creating a CustomResourceDefinition, it should look like this:

    @Test
    @DisplayName("Should Create CronTab CRD")
    void testCronTabCrd() throws IOException {
      // Given
      KubernetesClient client = server.getClient();
      CustomResourceDefinition cronTabCrd = client.apiextensions().v1()
        .customResourceDefinitions()
        .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yml")))
        .get();
      server.expect().post()
        .withPath("/apis/apiextensions.k8s.io/v1/customresourcedefinitions")
        .andReturn(HttpURLConnection.HTTP_OK, cronTabCrd)
        .once();
    
      // When
      CustomResourceDefinition createdCronTabCrd = client.apiextensions().v1()
        .customResourceDefinitions()
        .create(cronTabCrd);
    
      // Then
      assertNotNull(createdCronTabCrd);
    }
    

    Bdw, if you don't like setting REST expectations. Fabric8 Kubernetes Mock Server also has a CRUD mode which mock real Kubernetes APIServer. You can enable it like this:

    @Rule
    public KubernetesServer server = new KubernetesServer(true, true);
    

    then use it in test like this:

    @Test
    @DisplayName("Should Create CronTab CRD")
    void testCronTabCrd() throws IOException {
      // Given
      KubernetesClient client = server.getClient();
      CustomResourceDefinition cronTabCrd = client.apiextensions().v1()
        .customResourceDefinitions()
        .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yml")))
        .get();
    
      // When
      CustomResourceDefinition createdCronTabCrd = client.apiextensions().v1()
        .customResourceDefinitions()
        .create(cronTabCrd);
    
      // Then
      assertNotNull(createdCronTabCrd);
    }
    

    I added CustomResourceLoadAndCreateTest and CustomResourceLoadAndCreateCrudTest tests in my demo repository: https://github.com/r0haaaan/kubernetes-mockserver-demo