Back to Repositories

Testing Database Discovery Client Integration in Apollo Config

This integration test suite validates the DatabaseDiscoveryClient functionality without decorator implementation in Apollo Config. It focuses on service registration, discovery, and deregistration scenarios while testing cluster-specific behaviors and multiple instance management.

Test Coverage Overview

The test suite provides comprehensive coverage of service discovery operations without decorator patterns.

  • Service registration and discovery validation
  • Cluster-specific instance filtering
  • Multiple instance registration handling
  • Deregistration functionality testing
  • Edge cases for duplicate registrations

Implementation Analysis

The testing approach utilizes Spring’s TestPropertySource and ContextConfiguration for environment setup. It implements various test scenarios using JUnit framework with specific focus on DatabaseDiscoveryClient implementation without decorators.

  • Direct DatabaseDiscoveryClient interaction testing
  • Custom configuration class implementation
  • Spring Boot auto-configuration testing

Technical Details

  • JUnit test framework integration
  • Spring Boot test configuration
  • Custom ServiceInstance factory usage
  • TestPropertySource for environment configuration
  • Autowired component injection
  • Logger implementation for test tracking

Best Practices Demonstrated

The test suite exemplifies high-quality integration testing practices.

  • Clear test method naming conventions
  • Comprehensive assertion checking
  • Isolated test scenarios
  • Proper test cleanup
  • Configuration separation
  • Systematic service lifecycle testing

apolloconfig/apollo

apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryWithoutDecoratorIntegrationTest.java

            
/*
 * Copyright 2024 Apollo Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.ctrip.framework.apollo.biz.registry;

import static com.ctrip.framework.apollo.biz.registry.ServiceInstanceFactory.newServiceInstance;
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.ctrip.framework.apollo.biz.AbstractIntegrationTest;
import com.ctrip.framework.apollo.biz.registry.DatabaseDiscoveryWithoutDecoratorIntegrationTest.ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration;
import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceDiscoveryAutoConfiguration;
import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration;
import com.ctrip.framework.apollo.biz.registry.configuration.support.ApolloServiceDiscoveryProperties;
import com.ctrip.framework.apollo.biz.service.ServiceRegistryService;
import java.util.List;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;

/**
 * test when {@link DatabaseDiscoveryClient} doesn't warp by decorator.
 */
@TestPropertySource(
    properties = {
        "apollo.service.registry.enabled=true",
        "apollo.service.registry.cluster=default",
        "apollo.service.discovery.enabled=true",
        "spring.application.name=for-test-service",
        "server.port=10000",
        // close decorator
        "ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration.enabled=true",
    }
)
@ContextConfiguration(classes = {
    ApolloServiceRegistryAutoConfiguration.class,
    // notice that the order of classes is import
    // @AutoConfigureBefore(ApolloServiceDiscoveryAutoConfiguration.class) won't work when run test
    ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration.class,
    ApolloServiceDiscoveryAutoConfiguration.class,
})
public class DatabaseDiscoveryWithoutDecoratorIntegrationTest extends AbstractIntegrationTest {

  private final Logger log = LoggerFactory.getLogger(this.getClass());

  @Autowired
  private DatabaseServiceRegistry serviceRegistry;

  @Autowired
  private DatabaseDiscoveryClient discoveryClient;

  /**
   * discover one after register, and delete it
   */
  @Test
  public void registerThenDiscoveryThenDelete() {
    // register it
    String serviceName = "a-service";
    String uri = "http://192.168.1.20:8080/";
    String cluster = "default";
    ServiceInstance instance = newServiceInstance(
        serviceName, uri, cluster
    );
    this.serviceRegistry.register(instance);

    // find it
    List<ServiceInstance> serviceInstances = this.discoveryClient.getInstances(serviceName);
    assertEquals(1, serviceInstances.size());
    ServiceInstance actual = serviceInstances.get(0);
    assertEquals(serviceName, actual.getServiceName());
    assertEquals(uri, actual.getUri().toString());
    assertEquals(cluster, actual.getCluster());
    assertEquals(0, actual.getMetadata().size());

    // delete it
    this.serviceRegistry.deregister(instance);
    // find none
    assertEquals(0, this.discoveryClient.getInstances(serviceName).size());
  }

  /**
   * diff cluster so cannot be discover
   */
  @Test
  public void registerThenDiscoveryNone() {
    // register it
    String serviceName = "b-service";
    ServiceInstance instance = newServiceInstance(
        serviceName, "http://192.168.1.20:8080/", "cannot-be-discovery"
    );
    this.serviceRegistry.register(instance);

    // find none
    List<ServiceInstance> serviceInstances = this.discoveryClient.getInstances(serviceName);
    assertEquals(0, serviceInstances.size());
  }

  @Test
  public void registerTwice() {
    String serviceName = "c-service";
    ServiceInstance instance = newServiceInstance(
        serviceName, "http://192.168.1.20:8080/", "default"
    );

    // register it
    this.serviceRegistry.register(instance);
    // register again
    this.serviceRegistry.register(instance);

    // only discover one
    List<ServiceInstance> serviceInstances = this.discoveryClient.getInstances(serviceName);
    assertEquals(1, serviceInstances.size());
  }

  @Test
  public void registerTwoInstancesThenDeleteOne() {
    final String serviceName = "d-service";
    final String cluster = "default";

    this.serviceRegistry.register(
        newServiceInstance(
            serviceName, "http://192.168.1.20:8080/", cluster
        )
    );
    this.serviceRegistry.register(
        newServiceInstance(
            serviceName, "http://192.168.1.20:10000/", cluster
        )
    );

    final List<ServiceInstance> serviceInstances = this.discoveryClient.getInstances(serviceName);
    assertEquals(2, serviceInstances.size());

    for (ServiceInstance serviceInstance : serviceInstances) {
      assertEquals(serviceName, serviceInstance.getServiceName());
      assertEquals(cluster, serviceInstance.getCluster());
      assertEquals(0, serviceInstance.getMetadata().size());
    }

    // delete one
    this.serviceRegistry.deregister(
        newServiceInstance(
            serviceName, "http://192.168.1.20:10000/", cluster
        )
    );

    assertEquals(1, this.discoveryClient.getInstances(serviceName).size());
    assertEquals("http://192.168.1.20:8080/",
        this.discoveryClient.getInstances(serviceName).get(0).getUri().toString());
  }

  /**
   * only use in {@link DatabaseDiscoveryWithoutDecoratorIntegrationTest}
   */
  @Configuration
  @ConditionalOnProperty(prefix = "ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration", value = "enabled")
  @ConditionalOnBean(ApolloServiceDiscoveryAutoConfiguration.class)
  @AutoConfigureBefore(ApolloServiceDiscoveryAutoConfiguration.class)
  @EnableConfigurationProperties({
      ApolloServiceDiscoveryProperties.class,
  })
  static class ApolloServiceDiscoveryWithoutDecoratorAutoConfiguration {
    @Bean
    public DatabaseDiscoveryClient databaseDiscoveryClient(
        ApolloServiceDiscoveryProperties discoveryProperties,
        ServiceInstance selfServiceInstance,
        ServiceRegistryService serviceRegistryService
    ) {
      return new DatabaseDiscoveryClientImpl(
          serviceRegistryService, discoveryProperties, selfServiceInstance.getCluster()
      );
    }
  }
}