/* * Copyright 2015-present Facebook, Inc. * * 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.facebook.buck.slb; import com.facebook.buck.event.BuckEventBus; import com.facebook.buck.timing.Clock; import com.google.common.collect.ImmutableList; import java.io.IOException; import java.net.URI; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Dispatcher; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import org.easymock.Capture; import org.easymock.EasyMock; import org.easymock.EasyMockSupport; import org.easymock.IAnswer; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class ClientSideSlbTest extends EasyMockSupport { private static final ImmutableList<URI> SERVERS = ImmutableList.of( URI.create("http://localhost:4242"), URI.create("http://localhost:8484"), URI.create("http://localhost:2121")); private BuckEventBus mockBus; private Clock mockClock; private OkHttpClient mockClient; private ScheduledExecutorService mockScheduler; private ClientSideSlbConfig config; private Dispatcher dispatcher; // Apparently EasyMock does not deal very well with Generic Types using wildcard ?. // Several workarounds can be found on StackOverflow this one being the list intrusive. @SuppressWarnings("rawtypes") private ScheduledFuture mockFuture; @Before public void setUp() { mockBus = createNiceMock(BuckEventBus.class); mockFuture = createMock(ScheduledFuture.class); mockClient = createNiceMock(OkHttpClient.class); dispatcher = new Dispatcher(createMock(ExecutorService.class)); EasyMock.expect(mockClient.dispatcher()).andReturn(dispatcher).anyTimes(); mockScheduler = createMock(ScheduledExecutorService.class); mockClock = createMock(Clock.class); EasyMock.expect(mockClock.currentTimeMillis()).andReturn(42L).anyTimes(); config = ClientSideSlbConfig.builder() .setClock(mockClock) .setServerPool(SERVERS) .setEventBus(mockBus) .build(); } @Test @SuppressWarnings("unchecked") public void testBackgroundHealthCheckIsScheduled() { Capture<Runnable> capture = EasyMock.newCapture(); EasyMock.expect( mockScheduler.scheduleWithFixedDelay( EasyMock.capture(capture), EasyMock.anyLong(), EasyMock.anyLong(), EasyMock.anyObject(TimeUnit.class))) .andReturn(mockFuture) .once(); EasyMock.expect(mockFuture.cancel(true)).andReturn(true).once(); EasyMock.expect(mockScheduler.shutdownNow()).andReturn(ImmutableList.of()).once(); EasyMock.expect(dispatcher.executorService().shutdownNow()) .andReturn(ImmutableList.of()) .once(); replayAll(); try (ClientSideSlb slb = new ClientSideSlb(config, mockScheduler, mockClient)) { Assert.assertTrue(capture.hasCaptured()); } verifyAll(); } @Test @SuppressWarnings("unchecked") public void testAllServersArePinged() throws IOException { Capture<Runnable> capture = EasyMock.newCapture(); EasyMock.expect( mockScheduler.scheduleWithFixedDelay( EasyMock.capture(capture), EasyMock.anyLong(), EasyMock.anyLong(), EasyMock.anyObject(TimeUnit.class))) .andReturn(mockFuture) .once(); Call mockCall = createMock(Call.class); for (URI server : SERVERS) { EasyMock.expect(mockClient.newCall(EasyMock.anyObject(Request.class))).andReturn(mockCall); mockCall.enqueue(EasyMock.anyObject(ClientSideSlb.ServerPing.class)); EasyMock.expectLastCall() .andAnswer( new IAnswer<Object>() { @Override public Object answer() throws Throwable { Callback callback = (Callback) EasyMock.getCurrentArguments()[0]; ResponseBody body = ResponseBody.create(MediaType.parse("text/plain"), "The Body."); Response response = new Response.Builder() .body(body) .code(200) .protocol(Protocol.HTTP_1_1) .request(new Request.Builder().url(server.toString()).build()) .build(); callback.onResponse(mockCall, response); return null; } }); } mockBus.post(EasyMock.anyObject(LoadBalancerPingEvent.class)); EasyMock.expectLastCall(); EasyMock.expect(mockFuture.cancel(true)).andReturn(true).once(); EasyMock.expect(mockScheduler.shutdownNow()).andReturn(ImmutableList.of()).once(); EasyMock.expect(dispatcher.executorService().shutdownNow()) .andReturn(ImmutableList.of()) .once(); replayAll(); try (ClientSideSlb slb = new ClientSideSlb(config, mockScheduler, mockClient)) { Runnable healthCheckLoop = capture.getValue(); healthCheckLoop.run(); } verifyAll(); } }