/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.internal.cache;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.util.Properties;

import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.Statistics;
import org.apache.geode.StatisticsType;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.ResourceEvent;
import org.apache.geode.internal.cache.tier.Acceptor;
import org.apache.geode.internal.cache.tier.OverflowAttributes;
import org.apache.geode.internal.cache.tier.sockets.AcceptorBuilder;
import org.apache.geode.internal.cache.tier.sockets.CacheClientNotifier;
import org.apache.geode.internal.cache.tier.sockets.ClientHealthMonitor;
import org.apache.geode.internal.net.SocketCreator;
import org.apache.geode.internal.security.SecurityService;
import org.apache.geode.internal.statistics.StatisticsClockFactory;
import org.apache.geode.internal.statistics.StatisticsManager;
import org.apache.geode.test.junit.categories.ClientServerTest;

@Category(ClientServerTest.class)
public class CacheServerImplTest {

  private InternalCache cache;
  private CacheClientNotifier cacheClientNotifier;
  private ClientHealthMonitor clientHealthMonitor;
  private DistributionConfig config;
  private SecurityService securityService;
  private SocketCreator socketCreator;
  private InternalDistributedSystem system;
  private CacheServerAdvisor advisor;

  @Before
  public void setUp() throws IOException {
    cache = mock(InternalCache.class);
    cacheClientNotifier = mock(CacheClientNotifier.class);
    clientHealthMonitor = mock(ClientHealthMonitor.class);
    config = mock(DistributionConfig.class);
    securityService = mock(SecurityService.class);
    socketCreator = mock(SocketCreator.class);
    system = mock(InternalDistributedSystem.class);
    advisor = mock(CacheServerAdvisor.class);

    ServerSocket serverSocket = mock(ServerSocket.class);
    StatisticsManager statisticsManager = mock(StatisticsManager.class);

    when(cache.getDistributedSystem()).thenReturn(system);
    when(cache.getInternalDistributedSystem()).thenReturn(system);
    when(cache.getCacheTransactionManager()).thenReturn(mock(TXManagerImpl.class));
    when(serverSocket.getLocalSocketAddress()).thenReturn(mock(SocketAddress.class));
    when(socketCreator.createServerSocket(anyInt(), anyInt(), any(), any(), anyInt()))
        .thenReturn(serverSocket);
    when(statisticsManager.createAtomicStatistics(any(), any())).thenReturn(mock(Statistics.class));
    when(statisticsManager.createType(any(), any(), any())).thenReturn(mock(StatisticsType.class));
    when(system.getConfig()).thenReturn(config);
    when(system.getProperties()).thenReturn(new Properties());
    when(system.getStatisticsManager()).thenReturn(statisticsManager);
  }

  @Test
  public void createdAcceptorIsGatewayEndpoint() throws IOException {
    OverflowAttributes overflowAttributes = mock(OverflowAttributes.class);
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);

    Acceptor acceptor = server.createAcceptor(overflowAttributes);

    assertThat(acceptor.isGatewayReceiver()).isFalse();
  }

  @Test
  public void getGroups_returnsSpecifiedGroup() {
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);
    String specifiedGroup = "group0";

    server.setGroups(new String[] {specifiedGroup});

    assertThat(server.getGroups())
        .containsExactly(specifiedGroup);
  }

  @Test
  public void getGroups_returnsMultipleSpecifiedGroups() {
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);
    String specifiedGroup1 = "group1";
    String specifiedGroup2 = "group2";
    String specifiedGroup3 = "group3";

    server.setGroups(new String[] {specifiedGroup1, specifiedGroup2, specifiedGroup3});

    assertThat(server.getGroups())
        .containsExactlyInAnyOrder(specifiedGroup1, specifiedGroup2, specifiedGroup3);
  }

  @Test
  public void getCombinedGroups_includesMembershipGroup() {
    String membershipGroup = "group-m0";
    when(config.getGroups()).thenReturn(membershipGroup);
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);

    assertThat(server.getCombinedGroups())
        .contains(membershipGroup);
  }

  @Test
  public void getCombinedGroups_includesMultipleMembershipGroups() {
    String membershipGroup1 = "group-m1";
    String membershipGroup2 = "group-m2";
    String membershipGroup3 = "group-m3";
    when(config.getGroups())
        .thenReturn(membershipGroup1 + "," + membershipGroup2 + "," + membershipGroup3);
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);

    assertThat(server.getCombinedGroups())
        .contains(membershipGroup1, membershipGroup2, membershipGroup3);
  }

  @Test
  public void getCombinedGroups_includesSpecifiedGroupsAndMembershipGroups() {
    String membershipGroup1 = "group-m1";
    String membershipGroup2 = "group-m2";
    String membershipGroup3 = "group-m3";
    when(config.getGroups())
        .thenReturn(membershipGroup1 + "," + membershipGroup2 + "," + membershipGroup3);
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);
    String specifiedGroup1 = "group1";
    String specifiedGroup2 = "group2";
    String specifiedGroup3 = "group3";

    server.setGroups(new String[] {specifiedGroup1, specifiedGroup2, specifiedGroup3});

    assertThat(server.getCombinedGroups())
        .containsExactlyInAnyOrder(membershipGroup1, membershipGroup2, membershipGroup3,
            specifiedGroup1, specifiedGroup2, specifiedGroup3);
  }

  @Test
  public void startNotifiesResourceEventCacheServerStart() throws IOException {
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);

    server.start();

    verify(system).handleResourceEvent(same(ResourceEvent.CACHE_SERVER_START), same(server));
  }

  @Test
  public void stopNotifiesResourceEventCacheServerStart() throws IOException {
    InternalCacheServer server = new CacheServerImpl(cache, securityService,
        StatisticsClockFactory.disabledClock(), new AcceptorBuilder(),
        true, true, () -> socketCreator, (a, b, c, d, e, f, g, h, i) -> cacheClientNotifier,
        (a, b, c) -> clientHealthMonitor, a -> advisor);
    server.start();

    server.stop();

    verify(system).handleResourceEvent(same(ResourceEvent.CACHE_SERVER_STOP), same(server));
  }
}
