// TestControllerServicePorts verifies master extraServicePorts are
// correctly copied into controller
func TestControllerServicePorts(t *testing.T) {
	master, etcdserver, _, assert := setUp(t)
	defer etcdserver.Terminate(t)

	master.namespaceRegistry = namespace.NewRegistry(nil)
	master.serviceRegistry = registrytest.NewServiceRegistry()
	master.endpointRegistry = endpoint.NewRegistry(nil)

	master.ExtraServicePorts = []api.ServicePort{
		{
			Name:       "additional-port-1",
			Port:       1000,
			Protocol:   api.ProtocolTCP,
			TargetPort: intstr.FromInt(1000),
		},
		{
			Name:       "additional-port-2",
			Port:       1010,
			Protocol:   api.ProtocolTCP,
			TargetPort: intstr.FromInt(1010),
		},
	}

	controller := master.NewBootstrapController(EndpointReconcilerConfig{})

	assert.Equal(int32(1000), controller.ExtraServicePorts[0].Port)
	assert.Equal(int32(1010), controller.ExtraServicePorts[1].Port)
}
// TestNewBootstrapController verifies master fields are properly copied into controller
func TestNewBootstrapController(t *testing.T) {
	// Tests a subset of inputs to ensure they are set properly in the controller
	master, etcdserver, _, assert := setUp(t)
	defer etcdserver.Terminate(t)

	portRange := utilnet.PortRange{Base: 10, Size: 10}

	master.namespaceRegistry = namespace.NewRegistry(nil)
	master.serviceRegistry = registrytest.NewServiceRegistry()
	master.endpointRegistry = endpoint.NewRegistry(nil)

	master.ServiceNodePortRange = portRange
	master.MasterCount = 1
	master.ServiceReadWritePort = 1000
	master.PublicReadWritePort = 1010

	// test with an empty EndpointReconcilerConfig to ensure the defaults are applied
	controller := master.NewBootstrapController(EndpointReconcilerConfig{})

	assert.Equal(controller.NamespaceRegistry, master.namespaceRegistry)
	assert.Equal(controller.EndpointReconciler, NewMasterCountEndpointReconciler(master.MasterCount, master.endpointRegistry))
	assert.Equal(controller.EndpointInterval, DefaultEndpointReconcilerInterval)
	assert.Equal(controller.ServiceRegistry, master.serviceRegistry)
	assert.Equal(controller.ServiceNodePortRange, portRange)
	assert.Equal(controller.ServicePort, master.ServiceReadWritePort)
	assert.Equal(controller.PublicServicePort, master.PublicReadWritePort)

	// test with a filled-in EndpointReconcilerConfig to make sure its values are used
	controller = master.NewBootstrapController(EndpointReconcilerConfig{
		Reconciler: &fakeEndpointReconciler{},
		Interval:   5 * time.Second,
	})
	assert.Equal(controller.EndpointReconciler, &fakeEndpointReconciler{})
	assert.Equal(controller.EndpointInterval, 5*time.Second)
}
func TestRepairEmpty(t *testing.T) {
	_, cidr, _ := net.ParseCIDR("192.168.1.0/24")
	previous := ipallocator.NewCIDRRange(cidr)
	previous.Allocate(net.ParseIP("192.168.1.10"))

	var dst api.RangeAllocation
	err := previous.Snapshot(&dst)
	if err != nil {
		t.Fatal(err)
	}

	registry := registrytest.NewServiceRegistry()
	ipregistry := &mockRangeRegistry{
		item: &api.RangeAllocation{
			ObjectMeta: api.ObjectMeta{
				ResourceVersion: "1",
			},
			Range: dst.Range,
			Data:  dst.Data,
		},
	}
	r := NewRepair(0, registry, cidr, ipregistry)
	if err := r.RunOnce(); err != nil {
		t.Fatal(err)
	}
	after := ipallocator.NewCIDRRange(cidr)
	if err := after.Restore(cidr, ipregistry.updated.Data); err != nil {
		t.Fatal(err)
	}
	if after.Has(net.ParseIP("192.168.1.10")) {
		t.Errorf("unexpected ipallocator state: %#v", after)
	}
}
func TestRepairWithExisting(t *testing.T) {
	_, cidr, _ := net.ParseCIDR("192.168.1.0/24")
	previous := ipallocator.NewCIDRRange(cidr)

	var dst api.RangeAllocation
	err := previous.Snapshot(&dst)
	if err != nil {
		t.Fatal(err)
	}

	registry := registrytest.NewServiceRegistry()
	registry.List = api.ServiceList{
		Items: []api.Service{
			{
				Spec: api.ServiceSpec{ClusterIP: "192.168.1.1"},
			},
			{
				Spec: api.ServiceSpec{ClusterIP: "192.168.1.100"},
			},
			{ // outside CIDR, will be dropped
				Spec: api.ServiceSpec{ClusterIP: "192.168.0.1"},
			},
			{ // empty, ignored
				Spec: api.ServiceSpec{ClusterIP: ""},
			},
			{ // duplicate, dropped
				Spec: api.ServiceSpec{ClusterIP: "192.168.1.1"},
			},
			{ // headless
				Spec: api.ServiceSpec{ClusterIP: "None"},
			},
		},
	}

	ipregistry := &mockRangeRegistry{
		item: &api.RangeAllocation{
			ObjectMeta: api.ObjectMeta{
				ResourceVersion: "1",
			},
			Range: dst.Range,
			Data:  dst.Data,
		},
	}
	r := NewRepair(0, registry, cidr, ipregistry)
	if err := r.RunOnce(); err != nil {
		t.Fatal(err)
	}
	after := ipallocator.NewCIDRRange(cidr)
	if err := after.Restore(cidr, ipregistry.updated.Data); err != nil {
		t.Fatal(err)
	}
	if !after.Has(net.ParseIP("192.168.1.1")) || !after.Has(net.ParseIP("192.168.1.100")) {
		t.Errorf("unexpected ipallocator state: %#v", after)
	}
	if after.Free() != 252 {
		t.Errorf("unexpected ipallocator state: %#v", after)
	}
}
func TestRepair(t *testing.T) {
	registry := registrytest.NewServiceRegistry()
	_, cidr, _ := net.ParseCIDR("192.168.1.0/24")
	ipregistry := &mockRangeRegistry{
		item: &api.RangeAllocation{},
	}
	r := NewRepair(0, registry, cidr, ipregistry)

	if err := r.RunOnce(); err != nil {
		t.Fatal(err)
	}
	if !ipregistry.updateCalled || ipregistry.updated == nil || ipregistry.updated.Range != cidr.String() || ipregistry.updated != ipregistry.item {
		t.Errorf("unexpected ipregistry: %#v", ipregistry)
	}

	ipregistry = &mockRangeRegistry{
		item:      &api.RangeAllocation{},
		updateErr: fmt.Errorf("test error"),
	}
	r = NewRepair(0, registry, cidr, ipregistry)
	if err := r.RunOnce(); !strings.Contains(err.Error(), ": test error") {
		t.Fatal(err)
	}
}