Back to Repositories

Testing Database Service Discovery Integration in Apollo Config

This test suite validates the integration between Apollo’s database-based service discovery and registry components. It verifies service registration, discovery, and deregistration functionality while handling different clusters and multiple service instances.

Test Coverage Overview

The test suite provides comprehensive coverage of database-driven service discovery functionality.

Key areas tested include:
  • Service registration and discovery workflow
  • Cluster-based service filtering
  • Multiple instance registration
  • Service deregistration behavior
  • Edge cases like duplicate registrations

Implementation Analysis

The testing approach uses JUnit with Spring test context configuration to validate service discovery operations. It implements integration testing patterns using DatabaseServiceRegistry and DatabaseDiscoveryClient components, with specific property configurations for service registry and discovery features.

Framework features utilized include:
  • Spring TestPropertySource for configuration
  • ContextConfiguration for component setup
  • AbstractIntegrationTest extension for base functionality

Technical Details

Testing infrastructure includes:
  • JUnit test framework
  • Spring Test context support
  • SLF4J logging implementation
  • Custom ServiceInstance factory methods
  • Database-backed service registry
  • Configured test properties for service name, port, and cluster settings

Best Practices Demonstrated

The test suite showcases several testing best practices for integration testing.

Notable practices include:
  • Isolated test cases with clear purposes
  • Comprehensive assertion checking
  • Proper test setup and configuration
  • Clear test method naming conventions
  • Effective use of Spring testing annotations
  • Proper separation of test scenarios

apolloconfig/apollo

apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/registry/DatabaseDiscoveryIntegrationTest.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.configuration.ApolloServiceDiscoveryAutoConfiguration;
import com.ctrip.framework.apollo.biz.registry.configuration.ApolloServiceRegistryAutoConfiguration;
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.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;

/**
 * test when {@link DatabaseDiscoveryClient} is warped 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",
    }
)
@ContextConfiguration(classes = {
    ApolloServiceRegistryAutoConfiguration.class,
    ApolloServiceDiscoveryAutoConfiguration.class,
})
public class DatabaseDiscoveryIntegrationTest 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);
    // because it save in memory, so we can still find it
    assertEquals(1, 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
        )
    );

    // because it save in memory, so we can still find it
    assertEquals(2, this.discoveryClient.getInstances(serviceName).size());
  }
}