/*
 * Copyright (c) 2014 Spotify AB.
 *
 * 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.spotify.helios.agent;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

import com.spotify.helios.common.descriptors.PortMapping;

import org.junit.Test;

import java.net.ServerSocket;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

public class PortAllocatorTest {

  @Test
  public void testAllocate() throws Exception {
    final PortAllocator sut = new PortAllocator(20000, 20010);
    final Map<String, PortMapping> mapping = ImmutableMap.of("p1", PortMapping.of(17),
                                                             "p2", PortMapping.of(18, 18));
    final Set<Integer> used = ImmutableSet.of(10, 11);
    final Map<String, Integer> allocation = sut.allocate(mapping, used);
    assertEquals(ImmutableMap.of("p1", 20000, "p2", 18), allocation);
  }

  @Test
  public void testInsufficientPortsFail1() throws Exception {
    final PortAllocator sut = new PortAllocator(10, 11);
    final Map<String, PortMapping> mapping = ImmutableMap.of("p1", PortMapping.of(17),
                                                             "p2", PortMapping.of(18, 18));
    final Set<Integer> used = ImmutableSet.of(10, 11);
    final Map<String, Integer> allocation = sut.allocate(mapping, used);
    assertNull(allocation);
  }

  @Test
  public void testInsufficientPortsFail2() throws Exception {
    final PortAllocator sut = new PortAllocator(10, 11);
    final Map<String, PortMapping> mapping = ImmutableMap.of("p1", PortMapping.of(1),
                                                             "p2", PortMapping.of(2),
                                                             "p3", PortMapping.of(4),
                                                             "p4", PortMapping.of(18, 18));
    final Set<Integer> used = ImmutableSet.of();
    final Map<String, Integer> allocation = sut.allocate(mapping, used);
    assertNull(allocation);
  }

  @Test
  public void verifyStaticPortsNotCheckedAgainstRange() throws Exception {
    final PortAllocator sut = new PortAllocator(20000, 20001);
    final Map<String, PortMapping> mapping = ImmutableMap.of("p1", PortMapping.of(1),
                                                             "p2", PortMapping.of(18, 18));
    final Set<Integer> used = ImmutableSet.of();
    final Map<String, Integer> allocation = sut.allocate(mapping, used);
    assertEquals(ImmutableMap.of("p1", 20000, "p2", 18), allocation);
  }

  @Test
  public void testAllocateCheckSystem() throws Exception {
    final PortAllocator sut = new PortAllocator(20000, 20010);
    final Map<String, PortMapping> mapping = ImmutableMap.of("p1", PortMapping.of(17),
                                                             "p2", PortMapping.of(18, 20001));
    final Set<Integer> used = Collections.emptySet();

    // Occupy a port and check that Helios doesn't use it.
    new ServerSocket(20000);
    final Map<String, Integer> allocation = sut.allocate(mapping, used);
    assertEquals(ImmutableMap.of("p1", 20002, "p2", 20001), allocation);
  }
}

@@ -824,24 +824,16 @@
 ava.
-net.ServerSocket
+util.Map
 ;%0Aim
@@ -851,65 +851,255 @@
 til.
-Collections;%0Aimport java.util.Map;%0Aimport java.util.Set;%0A
+Set;%0A%0Aimport static org.hamcrest.Matchers.allOf;%0Aimport static org.hamcrest.Matchers.greaterThanOrEqualTo;%0Aimport static org.hamcrest.Matchers.hasEntry;%0Aimport static org.hamcrest.Matchers.is;%0Aimport static org.hamcrest.Matchers.lessThanOrEqualTo;
 %0Aimp
@@ -1132,22 +1132,20 @@
 t.assert
-Equals
+Null
 ;%0Aimport
@@ -1175,20 +1175,20 @@
 t.assert
-Null
+That
 ;%0A%0Apubli
@@ -1656,65 +1656,189 @@
 sert
-Equals(ImmutableMap.of(%22p1%22, 
+That(allocation, hasEntry(is(%22p1%22),%0A                                    allOf(greaterThanOrEqualTo(
 20000
+)
 , 
-%22p2%22, 18), allocation
+lessThanOrEqualTo(20010))));%0A    assertThat(allocation, hasEntry(%22p2%22, 18)
 );%0A 
@@ -3400,671 +3400,189 @@
 sert
-Equals(ImmutableMap.of(%22p1%22, 20000, %22p2%22, 18), allocation);%0A  %7D%0A%0A  @Test%0A  public void testAllocateCheckSystem() throws Exception %7B%0A    final PortAllocator sut = new PortAllocator(20000, 20010);%0A    final Map%3CString, PortMapping%3E mapping = ImmutableMap.of(%22p1%22, PortMapping.of(17),%0A                                                             %22p2%22, PortMapping.of(18, 20001));%0A    final Set%3CInteger%3E used = Collections.emptySet();%0A%0A    // Occupy a port and check that Helios doesn't use it.%0A    new ServerSocket
+That(allocation, hasEntry(is(%22p1%22),%0A                                    allOf(greaterThanOrEqualTo(20000), lessThanOrEqualTo
 (2000
-0
+1)))
 );%0A    
-final Map%3CString, Integer%3E allocation = sut.allocate(mapping, used);%0A    assertEquals(ImmutableMap.of(%22p1%22, 20002, %22p2%22, 20001), allocation
+assertThat(allocation, hasEntry(%22p2%22, 18)
 );%0A 

Fix test failure when port 20000 is occupied