Back to Repositories

Validating RestTemplate Thread Safety in Conductor-OSS

This test suite evaluates the DefaultRestTemplateProvider class in Conductor’s HTTP task implementation. It focuses on validating the thread-safety and instance management of RestTemplate objects, ensuring proper resource handling in multi-threaded environments.

Test Coverage Overview

The test suite covers critical aspects of RestTemplate provider functionality, focusing on thread isolation and object instance management.

  • Thread-specific RestTemplate instance creation
  • Object instance caching behavior
  • Thread safety validation
  • Timeout configuration verification

Implementation Analysis

The testing approach employs JUnit to verify thread-safe RestTemplate provisioning. It utilizes multi-threaded test scenarios to validate instance isolation and implements timing-sensitive operations with Duration configurations.

The tests demonstrate thread manipulation through explicit Thread creation and management, with careful synchronization using join() operations.

Technical Details

Testing infrastructure includes:

  • JUnit 4 test framework
  • Spring RestTemplate integration
  • Thread management utilities
  • Duration-based timeout configurations
  • StringBuilder for thread-safe result accumulation

Best Practices Demonstrated

The test suite exemplifies several testing best practices:

  • Isolated thread testing
  • Proper test method naming conventions
  • Clear separation of concerns
  • Explicit timeout configurations
  • Appropriate use of @Ignore for deprecated tests
  • Thread-safe result verification

conductor-oss/conductor

http-task/src/test/java/com/netflix/conductor/tasks/http/providers/DefaultRestTemplateProviderTest.java

            
/*
 * Copyright 2022 Conductor Authors.
 * <p>
 * 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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.netflix.conductor.tasks.http.providers;

import java.time.Duration;

import org.junit.Ignore;
import org.junit.Test;
import org.springframework.web.client.RestTemplate;

import com.netflix.conductor.tasks.http.HttpTask;

import static org.junit.Assert.*;

public class DefaultRestTemplateProviderTest {

    @Test
    public void differentObjectsForDifferentThreads() throws InterruptedException {
        DefaultRestTemplateProvider defaultRestTemplateProvider =
                new DefaultRestTemplateProvider(Duration.ofMillis(150), Duration.ofMillis(100));
        final RestTemplate restTemplate =
                defaultRestTemplateProvider.getRestTemplate(new HttpTask.Input());
        final StringBuilder result = new StringBuilder();
        Thread t1 =
                new Thread(
                        () -> {
                            RestTemplate restTemplate1 =
                                    defaultRestTemplateProvider.getRestTemplate(
                                            new HttpTask.Input());
                            if (restTemplate1 != restTemplate) {
                                result.append("different");
                            }
                        });
        t1.start();
        t1.join();
        assertEquals(result.toString(), "different");
    }

    @Test
    @Ignore("We can no longer do this and have customizable timeouts per HttpTask.")
    public void sameObjectForSameThread() {
        DefaultRestTemplateProvider defaultRestTemplateProvider =
                new DefaultRestTemplateProvider(Duration.ofMillis(150), Duration.ofMillis(100));
        RestTemplate client1 = defaultRestTemplateProvider.getRestTemplate(new HttpTask.Input());
        RestTemplate client2 = defaultRestTemplateProvider.getRestTemplate(new HttpTask.Input());
        assertSame(client1, client2);
        assertNotNull(client1);
    }
}