/*
Copyright 2014 Google Inc. All rights reserved.

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 service

import (
	"net"
	"testing"
)

func TestNew(t *testing.T) {
	if newIPAllocator(nil) != nil {
		t.Errorf("expected nil")
	}
	if newIPAllocator(&net.IPNet{}) != nil {
		t.Errorf("expected nil")
	}
	_, ipnet, err := net.ParseCIDR("93.76.0.0/22")
	if err != nil {
		t.Error(err)
	}
	ipa := newIPAllocator(ipnet)
	if ipa == nil {
		t.Errorf("expected non-nil")
	}
	if ipa.ipSpaceSize != 1024 {
		t.Errorf("wrong size for ipa.ipSpaceSize")
	}
	if ipa.used.Size() != 2 {
		t.Errorf("wrong size() for ipa.used")
	}
	if !ipa.used.Contains(net.ParseIP("93.76.0.0")) {
		t.Errorf("network address was not reserved")
	}
	if !ipa.used.Contains(net.ParseIP("93.76.3.255")) {
		t.Errorf("broadcast address was not reserved")
	}
}

func TestAllocate(t *testing.T) {
	_, ipnet, _ := net.ParseCIDR("93.76.0.0/22")
	ipa := newIPAllocator(ipnet)

	if err := ipa.Allocate(net.ParseIP("93.76.0.0")); err == nil {
		t.Errorf("expected failure")
	}

	if err := ipa.Allocate(net.ParseIP("93.76.3.255")); err == nil {
		t.Errorf("expected failure")
	}

	if err := ipa.Allocate(net.ParseIP("93.76.0.1")); err != nil {
		t.Errorf("expected success, got %s", err)
	}

	if ipa.Allocate(net.ParseIP("93.76.0.1")) == nil {
		t.Errorf("expected failure")
	}

	if ipa.Allocate(net.ParseIP("1.2.3.4")) == nil {
		t.Errorf("expected failure")
	}
}

func TestAllocateNext(t *testing.T) {
	_, ipnet, _ := net.ParseCIDR("93.76.0.0/22")
	ipa := newIPAllocator(ipnet)

	// Turn off random allocation attempts, so we just allocate in sequence
	ipa.randomAttempts = 0

	ip1, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	if !ip1.Equal(net.ParseIP("93.76.0.1")) {
		t.Errorf("expected 93.76.0.1, got %s", ip1)
	}

	ip2, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	if !ip2.Equal(net.ParseIP("93.76.0.2")) {
		t.Errorf("expected 93.76.0.2, got %s", ip2)
	}

	// Burn a bunch of addresses.
	for i := 3; i < 256; i++ {
		ipa.AllocateNext()
	}

	ip256, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	if !ip256.Equal(net.ParseIP("93.76.1.0")) {
		t.Errorf("expected 93.76.1.0, got %s", ip256)
	}

	ip257, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	if !ip257.Equal(net.ParseIP("93.76.1.1")) {
		t.Errorf("expected 93.76.1.1, got %s", ip257)
	}

	// Burn a bunch of addresses.
	for i := 258; i < 1022; i++ {
		ipa.AllocateNext()
	}

	ip1022, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	if !ip1022.Equal(net.ParseIP("93.76.3.254")) {
		t.Errorf("expected 93.76.3.254, got %s", ip1022)
	}

	_, err = ipa.AllocateNext()
	if err == nil {
		t.Errorf("Expected nil - allocator is full")
	}
}

func TestRelease(t *testing.T) {
	_, ipnet, _ := net.ParseCIDR("93.76.0.0/24")
	ipa := newIPAllocator(ipnet)

	ipa.randomAttempts = 0

	err := ipa.Release(net.ParseIP("1.2.3.4"))
	if err == nil {
		t.Errorf("Expected an error")
	}

	ip1, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	ip2, err := ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}
	_, err = ipa.AllocateNext()
	if err != nil {
		t.Error(err)
	}

	err = ipa.Release(ip2)
	if err != nil {
		t.Error(err)
	}

	ip4, err := ipa.AllocateNext()
	if !ip4.Equal(ip2) {
		t.Errorf("Expected %s, got %s", ip2, ip4)
	}

	// Burn a bunch of addresses.
	for i := 4; i < 255; i++ {
		ipa.AllocateNext()
	}
	_, err = ipa.AllocateNext()
	if err == nil {
		t.Errorf("Expected an error")
	}
	ipa.Release(ip1)

	ip5, err := ipa.AllocateNext()
	if !ip5.Equal(ip1) {
		t.Errorf("Expected %s, got %s", ip1, ip5)
	}
}

func TestIPAdd(t *testing.T) {
	testCases := []struct {
		ip       string
		offset   int
		expected string
	}{
		{"1.2.3.0", 0, "1.2.3.0"},
		{"1.2.3.0", 1, "1.2.3.1"},
		{"1.2.3.0", 255, "1.2.3.255"},
		{"1.2.3.1", 255, "1.2.4.0"},
		{"1.2.3.2", 255, "1.2.4.1"},
		{"1.2.3.0", 256, "1.2.4.0"},
		{"1.2.3.0", 257, "1.2.4.1"},
		{"1.2.3.0", 65536, "1.3.3.0"},
		{"1.2.3.4", 1, "1.2.3.5"},
		{"255.255.255.255", 1, "0.0.0.0"},
		{"255.255.255.255", 2, "0.0.0.1"},
	}
	for _, tc := range testCases {
		r := ipAdd(net.ParseIP(tc.ip), tc.offset)
		if !r.Equal(net.ParseIP(tc.expected)) {
			t.Errorf("Expected %s, got %s", tc.expected, r)
		}
	}
}

func TestGenerateFirstTwoIPsFromSubnet(t *testing.T) {
	// Arrange
	testCases := []struct {
		subnet        string
		expected1stIP string
		expected2ndIP string
	}{
		{"10.0.0.0/24", "10.0.0.1", "10.0.0.2"},
		{"10.10.10.10/24", "10.10.10.1", "10.10.10.2"},
		{"10.10.10.10/16", "10.10.0.1", "10.10.0.2"},
		{"10.10.10.10/8", "10.0.0.1", "10.0.0.2"},
		{"10.10.10.10/0", "0.0.0.1", "0.0.0.2"},
		{"192.168.100.1/16", "192.168.0.1", "192.168.0.2"},
		{"153.15.250.5/23", "153.15.250.1", "153.15.250.2"},
		{"2001:db8::/48", "2001:db8::1", "2001:db8::2"},
		{"2001:db8:123:255::/48", "2001:db8:123::1", "2001:db8:123::2"},
		{"12.12.0.0/30", "12.12.0.1", "12.12.0.2"},
	}

	// Act & Assert
	for _, testCase := range testCases {
		_, subnet, _ := net.ParseCIDR(testCase.subnet)
		firstIP, err := GetIndexedIP(subnet, 1)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
		}
		secondIP, err := GetIndexedIP(subnet, 2)
		if err != nil {
			t.Errorf("Unexpected error: %v", err)
		}
		if firstIP.String() != testCase.expected1stIP {
			t.Errorf("Unexpected first IP: Expected <%q> Actual <%q>", testCase.expected1stIP, firstIP.String())
		}
		if secondIP.String() != testCase.expected2ndIP {
			t.Errorf("Unexpected second IP: Expected <%q> Actual <%q>", testCase.expected2ndIP, secondIP.String())
		}
	}
}

func TestGetIndexedIPSubnetTooSmall(t *testing.T) {
	// Arrange
	testCases := []struct {
		subnet string
	}{
		{"12.12.0.0/32"},
		{"12.12.0.0/31"},
	}

	// Act & Assert
	for _, testCase := range testCases {
		_, subnet, _ := net.ParseCIDR(testCase.subnet)
		secondIP, err := GetIndexedIP(subnet, 2)
		if err == nil {
			t.Errorf("Expected error but no error occured for subnet: %s", testCase.subnet)
		}
		thirdIP, err := GetIndexedIP(subnet, 3)
		if err == nil {
			t.Errorf("Expected error but no error occured for subnet: %s", testCase.subnet)
		}
		if secondIP != nil {
			t.Errorf("Unexpected second IP: Expected nil Actual <%q>", thirdIP.String())
		}
		if thirdIP != nil {
			t.Errorf("Unexpected third IP: Expected nil Actual <%q>", secondIP.String())
		}

	}
}

func TestCopyIP(t *testing.T) {
	ip1 := net.ParseIP("1.2.3.4")
	ip2 := copyIP(ip1)
	ip2[0]++
	if ip1[0] == ip2[0] {
		t.Errorf("copyIP did not copy")
	}
}

func TestSimplifyIP(t *testing.T) {
	ip4 := net.ParseIP("1.2.3.4")
	if len(ip4) != 16 {
		t.Errorf("expected 16 bytes")
	}
	if len(simplifyIP(ip4)) != 4 {
		t.Errorf("expected 4 bytes")
	}
	ip6 := net.ParseIP("::1.2.3.4")
	if len(ip6) != 16 {
		t.Errorf("expected 16 bytes")
	}
	if len(simplifyIP(ip6)) != 16 {
		t.Errorf("expected 16 bytes")
	}
	if simplifyIP([]byte{0, 0}) != nil {
		t.Errorf("expected nil")
	}
}
