Replace godep with dep

This commit is contained in:
Manuel de Brito Fontes 2017-10-06 17:26:14 -03:00
parent 1e7489927c
commit bf5616c65b
14883 changed files with 3937406 additions and 361781 deletions

View file

@ -16,4 +16,4 @@ limitations under the License.
// Package gce is an implementation of Interface, LoadBalancer
// and Instances for Google Compute Engine.
package gce
package gce // import "k8s.io/kubernetes/pkg/cloudprovider/providers/gce"

View file

@ -0,0 +1,137 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
computebeta "google.golang.org/api/compute/v0.beta"
)
const testSvcName = "my-service"
const testRegion = "us-central1"
const testSubnet = "/projects/x/testRegions/us-central1/testSubnetworks/customsub"
const testLBName = "a111111111111111"
// TestAddressManagerNoRequestedIP tests the typical case of passing in no requested IP
func TestAddressManagerNoRequestedIP(t *testing.T) {
svc := NewFakeCloudAddressService()
targetIP := ""
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
testHoldAddress(t, mgr, svc, testLBName, testRegion, targetIP, string(schemeInternal))
testReleaseAddress(t, mgr, svc, testLBName, testRegion)
}
// TestAddressManagerBasic tests the typical case of reserving and unreserving an address.
func TestAddressManagerBasic(t *testing.T) {
svc := NewFakeCloudAddressService()
targetIP := "1.1.1.1"
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
testHoldAddress(t, mgr, svc, testLBName, testRegion, targetIP, string(schemeInternal))
testReleaseAddress(t, mgr, svc, testLBName, testRegion)
}
// TestAddressManagerOrphaned tests the case where the address exists with the IP being equal
// to the requested address (forwarding rule or loadbalancer IP).
func TestAddressManagerOrphaned(t *testing.T) {
svc := NewFakeCloudAddressService()
targetIP := "1.1.1.1"
addr := &computebeta.Address{Name: testLBName, Address: targetIP, AddressType: string(schemeInternal)}
err := svc.ReserveBetaRegionAddress(addr, testRegion)
require.NoError(t, err)
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
testHoldAddress(t, mgr, svc, testLBName, testRegion, targetIP, string(schemeInternal))
testReleaseAddress(t, mgr, svc, testLBName, testRegion)
}
// TestAddressManagerOutdatedOrphan tests the case where an address exists but points to
// an IP other than the forwarding rule or loadbalancer IP.
func TestAddressManagerOutdatedOrphan(t *testing.T) {
svc := NewFakeCloudAddressService()
previousAddress := "1.1.0.0"
targetIP := "1.1.1.1"
addr := &computebeta.Address{Name: testLBName, Address: previousAddress, AddressType: string(schemeExternal)}
err := svc.ReserveBetaRegionAddress(addr, testRegion)
require.NoError(t, err)
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
testHoldAddress(t, mgr, svc, testLBName, testRegion, targetIP, string(schemeInternal))
testReleaseAddress(t, mgr, svc, testLBName, testRegion)
}
// TestAddressManagerExternallyOwned tests the case where the address exists but isn't
// owned by the controller.
func TestAddressManagerExternallyOwned(t *testing.T) {
svc := NewFakeCloudAddressService()
targetIP := "1.1.1.1"
addr := &computebeta.Address{Name: "my-important-address", Address: targetIP, AddressType: string(schemeInternal)}
err := svc.ReserveBetaRegionAddress(addr, testRegion)
require.NoError(t, err)
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
ipToUse, err := mgr.HoldAddress()
require.NoError(t, err)
assert.NotEmpty(t, ipToUse)
_, err = svc.GetRegionAddress(testLBName, testRegion)
assert.True(t, isNotFound(err))
testReleaseAddress(t, mgr, svc, testLBName, testRegion)
}
// TestAddressManagerExternallyOwned tests the case where the address exists but isn't
// owned by the controller. However, this address has the wrong type.
func TestAddressManagerBadExternallyOwned(t *testing.T) {
svc := NewFakeCloudAddressService()
targetIP := "1.1.1.1"
addr := &computebeta.Address{Name: "my-important-address", Address: targetIP, AddressType: string(schemeExternal)}
err := svc.ReserveBetaRegionAddress(addr, testRegion)
require.NoError(t, err)
mgr := newAddressManager(svc, testSvcName, testRegion, testSubnet, testLBName, targetIP, schemeInternal)
_, err = mgr.HoldAddress()
assert.NotNil(t, err)
}
func testHoldAddress(t *testing.T, mgr *addressManager, svc CloudAddressService, name, region, targetIP, scheme string) {
ipToUse, err := mgr.HoldAddress()
require.NoError(t, err)
assert.NotEmpty(t, ipToUse)
addr, err := svc.GetBetaRegionAddress(name, region)
require.NoError(t, err)
if targetIP != "" {
assert.EqualValues(t, targetIP, addr.Address)
}
assert.EqualValues(t, scheme, addr.AddressType)
}
func testReleaseAddress(t *testing.T, mgr *addressManager, svc CloudAddressService, name, region string) {
err := mgr.ReleaseAddress()
require.NoError(t, err)
_, err = svc.GetBetaRegionAddress(name, region)
assert.True(t, isNotFound(err))
}

View file

@ -0,0 +1,70 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/stretchr/testify/assert"
)
func TestServiceNetworkTierAnnotationKey(t *testing.T) {
createTestService := func() *v1.Service {
return &v1.Service{
ObjectMeta: metav1.ObjectMeta{
UID: "randome-uid",
Name: "test-svc",
Namespace: "test-ns",
},
}
}
for testName, testCase := range map[string]struct {
annotations map[string]string
expectedTier NetworkTier
expectErr bool
}{
"Use the default when the annotation does not exist": {
annotations: nil,
expectedTier: NetworkTierDefault,
},
"Standard tier": {
annotations: map[string]string{NetworkTierAnnotationKey: "Standard"},
expectedTier: NetworkTierStandard,
},
"Premium tier": {
annotations: map[string]string{NetworkTierAnnotationKey: "Premium"},
expectedTier: NetworkTierPremium,
},
"Report an error on invalid network tier value": {
annotations: map[string]string{NetworkTierAnnotationKey: "Unknown-tier"},
expectedTier: NetworkTierPremium,
expectErr: true,
},
} {
t.Run(testName, func(t *testing.T) {
svc := createTestService()
svc.Annotations = testCase.annotations
actualTier, err := GetServiceNetworkTier(svc)
assert.Equal(t, testCase.expectedTier, actualTier)
assert.Equal(t, testCase.expectErr, err != nil)
})
}
}

View file

@ -0,0 +1,927 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"testing"
"fmt"
computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1"
"google.golang.org/api/googleapi"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/cloudprovider"
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
)
// TODO TODO write a test for GetDiskByNameUnknownZone and make sure casting logic works
// TODO TODO verify that RegionDisks.Get does not return non-replica disks
func TestCreateDisk_Basic(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
projectID: gceProjectId,
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
zone := "zone1"
const sizeGb int64 = 128
tags := make(map[string]string)
tags["test-tag"] = "test-value"
expectedDiskTypeURI := gceComputeAPIEndpoint + "projects/" + fmt.Sprintf(
diskTypeURITemplateSingleZone, gceProjectId, zone, diskType)
expectedDescription := "{\"test-tag\":\"test-value\"}"
/* Act */
err := gce.CreateDisk(diskName, diskType, zone, sizeGb, tags)
/* Assert */
if err != nil {
t.Error(err)
}
if !fakeManager.createDiskCalled {
t.Error("Never called GCE disk create.")
}
if !fakeManager.doesOpMatch {
t.Error("Ops used in WaitForZoneOp does not match what's returned by CreateDisk.")
}
// Partial check of equality between disk description sent to GCE and parameters of method.
diskToCreate := fakeManager.diskToCreateStable
if diskToCreate.Name != diskName {
t.Errorf("Expected disk name: %s; Actual: %s", diskName, diskToCreate.Name)
}
if diskToCreate.Type != expectedDiskTypeURI {
t.Errorf("Expected disk type: %s; Actual: %s", expectedDiskTypeURI, diskToCreate.Type)
}
if diskToCreate.SizeGb != sizeGb {
t.Errorf("Expected disk size: %d; Actual: %d", sizeGb, diskToCreate.SizeGb)
}
if diskToCreate.Description != expectedDescription {
t.Errorf("Expected tag string: %s; Actual: %s", expectedDescription, diskToCreate.Description)
}
}
func TestCreateRegionalDisk_Basic(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{GCEDiskAlphaFeatureGate})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1", "zone3", "zone2"},
projectID: gceProjectId,
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
replicaZones := sets.NewString("zone1", "zone2")
const sizeGb int64 = 128
tags := make(map[string]string)
tags["test-tag"] = "test-value"
expectedDiskTypeURI := gceComputeAPIEndpointAlpha + "projects/" + fmt.Sprintf(
diskTypeURITemplateRegional, gceProjectId, gceRegion, diskType)
expectedDescription := "{\"test-tag\":\"test-value\"}"
/* Act */
err := gce.CreateRegionalDisk(diskName, diskType, replicaZones, sizeGb, tags)
/* Assert */
if err != nil {
t.Error(err)
}
if !fakeManager.createDiskCalled {
t.Error("Never called GCE disk create.")
}
if !fakeManager.doesOpMatch {
t.Error("Ops used in WaitForZoneOp does not match what's returned by CreateDisk.")
}
// Partial check of equality between disk description sent to GCE and parameters of method.
diskToCreate := fakeManager.diskToCreateStable
if diskToCreate.Name != diskName {
t.Errorf("Expected disk name: %s; Actual: %s", diskName, diskToCreate.Name)
}
if diskToCreate.Type != expectedDiskTypeURI {
t.Errorf("Expected disk type: %s; Actual: %s", expectedDiskTypeURI, diskToCreate.Type)
}
if diskToCreate.SizeGb != sizeGb {
t.Errorf("Expected disk size: %d; Actual: %d", sizeGb, diskToCreate.SizeGb)
}
if diskToCreate.Description != expectedDescription {
t.Errorf("Expected tag string: %s; Actual: %s", expectedDescription, diskToCreate.Description)
}
}
func TestCreateDisk_DiskAlreadyExists(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
AlphaFeatureGate: alphaFeatureGate,
}
// Inject disk AlreadyExists error.
alreadyExistsError := googleapi.ErrorItem{Reason: "alreadyExists"}
fakeManager.waitForOpError = &googleapi.Error{
Errors: []googleapi.ErrorItem{alreadyExistsError},
}
/* Act */
err := gce.CreateDisk("disk", DiskTypeSSD, "zone1", 128, nil)
/* Assert */
if err != nil {
t.Error(
"Expected success when a disk with the given name already exists, but an error is returned.")
}
}
func TestCreateDisk_WrongZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
gce := GCECloud{manager: fakeManager, managedZones: []string{"zone1"}}
diskName := "disk"
diskType := DiskTypeSSD
const sizeGb int64 = 128
/* Act */
err := gce.CreateDisk(diskName, diskType, "zone2", sizeGb, nil)
/* Assert */
if err == nil {
t.Error("Expected error when zone is not managed, but none returned.")
}
}
func TestCreateDisk_NoManagedZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
gce := GCECloud{manager: fakeManager, managedZones: []string{}}
diskName := "disk"
diskType := DiskTypeSSD
const sizeGb int64 = 128
/* Act */
err := gce.CreateDisk(diskName, diskType, "zone1", sizeGb, nil)
/* Assert */
if err == nil {
t.Error("Expected error when managedZones is empty, but none returned.")
}
}
func TestCreateDisk_BadDiskType(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
gce := GCECloud{manager: fakeManager, managedZones: []string{"zone1"}}
diskName := "disk"
diskType := "arbitrary-disk"
zone := "zone1"
const sizeGb int64 = 128
/* Act */
err := gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
/* Assert */
if err == nil {
t.Error("Expected error when disk type is not supported, but none returned.")
}
}
func TestCreateDisk_MultiZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1", "zone2", "zone3"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeStandard
const sizeGb int64 = 128
/* Act & Assert */
for _, zone := range gce.managedZones {
diskName = zone + "disk"
err := gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
if err != nil {
t.Errorf("Error creating disk in zone '%v'; error: \"%v\"", zone, err)
}
}
}
func TestDeleteDisk_Basic(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
zone := "zone1"
const sizeGb int64 = 128
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
/* Act */
err := gce.DeleteDisk(diskName)
/* Assert */
if err != nil {
t.Error(err)
}
if !fakeManager.deleteDiskCalled {
t.Error("Never called GCE disk delete.")
}
if !fakeManager.doesOpMatch {
t.Error("Ops used in WaitForZoneOp does not match what's returned by DeleteDisk.")
}
}
func TestDeleteDisk_NotFound(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
/* Act */
err := gce.DeleteDisk(diskName)
/* Assert */
if err != nil {
t.Error("Expected successful operation when disk is not found, but an error is returned.")
}
}
func TestDeleteDisk_ResourceBeingUsed(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
zone := "zone1"
const sizeGb int64 = 128
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
fakeManager.resourceInUse = true
/* Act */
err := gce.DeleteDisk(diskName)
/* Assert */
if err == nil {
t.Error("Expected error when disk is in use, but none returned.")
}
}
func TestDeleteDisk_SameDiskMultiZone(t *testing.T) {
/* Assert */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1", "zone2", "zone3"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
const sizeGb int64 = 128
for _, zone := range gce.managedZones {
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
}
/* Act */
// DeleteDisk will call FakeServiceManager.GetDisk() with all zones,
// and FakeServiceManager.GetDisk() always returns a disk,
// so DeleteDisk thinks a disk with diskName exists in all zones.
err := gce.DeleteDisk(diskName)
/* Assert */
if err == nil {
t.Error("Expected error when disk is found in multiple zones, but none returned.")
}
}
func TestDeleteDisk_DiffDiskMultiZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"zone1"},
AlphaFeatureGate: alphaFeatureGate,
}
diskName := "disk"
diskType := DiskTypeSSD
const sizeGb int64 = 128
for _, zone := range gce.managedZones {
diskName = zone + "disk"
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
}
/* Act & Assert */
var err error
for _, zone := range gce.managedZones {
diskName = zone + "disk"
err = gce.DeleteDisk(diskName)
if err != nil {
t.Errorf("Error deleting disk in zone '%v'; error: \"%v\"", zone, err)
}
}
}
func TestGetAutoLabelsForPD_Basic(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "us-central1"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
diskType := DiskTypeSSD
zone := "us-central1-c"
const sizeGb int64 = 128
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{zone},
AlphaFeatureGate: alphaFeatureGate,
}
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
/* Act */
labels, err := gce.GetAutoLabelsForPD(diskName, zone)
/* Assert */
if err != nil {
t.Error(err)
}
if labels[kubeletapis.LabelZoneFailureDomain] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[kubeletapis.LabelZoneFailureDomain], zone)
}
if labels[kubeletapis.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-central1'", labels[kubeletapis.LabelZoneRegion])
}
}
func TestGetAutoLabelsForPD_NoZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "europe-west1"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
diskType := DiskTypeStandard
zone := "europe-west1-d"
const sizeGb int64 = 128
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{zone},
AlphaFeatureGate: alphaFeatureGate,
}
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
/* Act */
labels, err := gce.GetAutoLabelsForPD(diskName, "")
/* Assert */
if err != nil {
t.Error(err)
}
if labels[kubeletapis.LabelZoneFailureDomain] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[kubeletapis.LabelZoneFailureDomain], zone)
}
if labels[kubeletapis.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'europe-west1'", labels[kubeletapis.LabelZoneRegion])
}
}
func TestGetAutoLabelsForPD_DiskNotFound(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
zone := "asia-northeast1-a"
gce := GCECloud{manager: fakeManager, managedZones: []string{zone}}
/* Act */
_, err := gce.GetAutoLabelsForPD(diskName, zone)
/* Assert */
if err == nil {
t.Error("Expected error when the specified disk does not exist, but none returned.")
}
}
func TestGetAutoLabelsForPD_DiskNotFoundAndNoZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{},
AlphaFeatureGate: alphaFeatureGate,
}
/* Act */
_, err := gce.GetAutoLabelsForPD(diskName, "")
/* Assert */
if err == nil {
t.Error("Expected error when the specified disk does not exist, but none returned.")
}
}
func TestGetAutoLabelsForPD_DupDisk(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "us-west1"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
diskType := DiskTypeStandard
zone := "us-west1-b"
const sizeGb int64 = 128
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"us-west1-b", "asia-southeast1-a"},
AlphaFeatureGate: alphaFeatureGate,
}
for _, zone := range gce.managedZones {
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
}
/* Act */
labels, err := gce.GetAutoLabelsForPD(diskName, zone)
/* Assert */
if err != nil {
t.Error("Disk name and zone uniquely identifies a disk, yet an error is returned.")
}
if labels[kubeletapis.LabelZoneFailureDomain] != zone {
t.Errorf("Failure domain is '%v', but zone is '%v'",
labels[kubeletapis.LabelZoneFailureDomain], zone)
}
if labels[kubeletapis.LabelZoneRegion] != gceRegion {
t.Errorf("Region is '%v', but region is 'us-west1'", labels[kubeletapis.LabelZoneRegion])
}
}
func TestGetAutoLabelsForPD_DupDiskNoZone(t *testing.T) {
/* Arrange */
gceProjectId := "test-project"
gceRegion := "fake-region"
fakeManager := newFakeManager(gceProjectId, gceRegion)
diskName := "disk"
diskType := DiskTypeStandard
const sizeGb int64 = 128
alphaFeatureGate, featureGateErr := NewAlphaFeatureGate([]string{})
if featureGateErr != nil {
t.Error(featureGateErr)
}
gce := GCECloud{
manager: fakeManager,
managedZones: []string{"us-west1-b", "asia-southeast1-a"},
AlphaFeatureGate: alphaFeatureGate,
}
for _, zone := range gce.managedZones {
gce.CreateDisk(diskName, diskType, zone, sizeGb, nil)
}
/* Act */
_, err := gce.GetAutoLabelsForPD(diskName, "")
/* Assert */
if err == nil {
t.Error("Expected error when the disk is duplicated and zone is not specified, but none returned.")
}
}
type targetClientAPI int
const (
targetStable targetClientAPI = iota
targetBeta
targetAlpha
)
type FakeServiceManager struct {
// Common fields shared among tests
targetAPI targetClientAPI
gceProjectID string
gceRegion string
opAlpha *computealpha.Operation // Mocks an operation returned by GCE API calls
opBeta *computebeta.Operation // Mocks an operation returned by GCE API calls
opStable *compute.Operation // Mocks an operation returned by GCE API calls
doesOpMatch bool
zonalDisks map[string]string // zone: diskName
regionalDisks map[string]sets.String // diskName: zones
waitForOpError error // Error to be returned by WaitForZoneOp or WaitForRegionalOp
// Fields for TestCreateDisk
createDiskCalled bool
diskToCreateAlpha *computealpha.Disk
diskToCreateBeta *computebeta.Disk
diskToCreateStable *compute.Disk
// Fields for TestDeleteDisk
deleteDiskCalled bool
resourceInUse bool // Marks the disk as in-use
}
func newFakeManager(gceProjectID string, gceRegion string) *FakeServiceManager {
return &FakeServiceManager{
zonalDisks: make(map[string]string),
regionalDisks: make(map[string]sets.String),
gceProjectID: gceProjectID,
gceRegion: gceRegion,
}
}
/**
* Upon disk creation, disk info is stored in FakeServiceManager
* to be used by other tested methods.
*/
func (manager *FakeServiceManager) CreateDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zone string) (gceObject, error) {
manager.createDiskCalled = true
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
diskTypeURI := gceComputeAPIEndpoint + "projects/" + fmt.Sprintf(diskTypeURITemplateSingleZone, manager.gceProjectID, zone, diskType)
diskToCreateV1 := &compute.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
manager.diskToCreateStable = diskToCreateV1
manager.zonalDisks[zone] = diskToCreateV1.Name
return manager.opStable, nil
case targetBeta:
manager.opBeta = &computebeta.Operation{}
diskTypeURI := gceComputeAPIEndpoint + "projects/" + fmt.Sprintf(diskTypeURITemplateSingleZone, manager.gceProjectID, zone, diskType)
diskToCreateBeta := &computebeta.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
manager.diskToCreateBeta = diskToCreateBeta
manager.zonalDisks[zone] = diskToCreateBeta.Name
return manager.opBeta, nil
case targetAlpha:
manager.opAlpha = &computealpha.Operation{}
diskTypeURI := gceComputeAPIEndpointAlpha + "projects/" + fmt.Sprintf(diskTypeURITemplateSingleZone, manager.gceProjectID, zone, diskType)
diskToCreateAlpha := &computealpha.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
manager.diskToCreateAlpha = diskToCreateAlpha
manager.zonalDisks[zone] = diskToCreateAlpha.Name
return manager.opAlpha, nil
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
/**
* Upon disk creation, disk info is stored in FakeServiceManager
* to be used by other tested methods.
*/
func (manager *FakeServiceManager) CreateRegionalDisk(
name string,
sizeGb int64,
tagsStr string,
diskType string,
zones sets.String) (gceObject, error) {
manager.createDiskCalled = true
diskTypeURI := gceComputeAPIEndpointAlpha + "projects/" + fmt.Sprintf(diskTypeURITemplateRegional, manager.gceProjectID, manager.gceRegion, diskType)
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
diskToCreateV1 := &compute.Disk{
Name: name,
SizeGb: sizeGb,
Description: tagsStr,
Type: diskTypeURI,
}
manager.diskToCreateStable = diskToCreateV1
manager.regionalDisks[diskToCreateV1.Name] = zones
return manager.opStable, nil
case targetBeta:
return nil, fmt.Errorf("RegionalDisk CreateDisk op not supported in beta.")
case targetAlpha:
return nil, fmt.Errorf("RegionalDisk CreateDisk op not supported in alpha.")
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
func (manager *FakeServiceManager) AttachDisk(
disk *GCEDisk,
readWrite string,
instanceZone string,
instanceName string) (gceObject, error) {
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
return manager.opStable, nil
case targetBeta:
manager.opBeta = &computebeta.Operation{}
return manager.opBeta, nil
case targetAlpha:
manager.opAlpha = &computealpha.Operation{}
return manager.opAlpha, nil
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
func (manager *FakeServiceManager) DetachDisk(
instanceZone string,
instanceName string,
devicePath string) (gceObject, error) {
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
return manager.opStable, nil
case targetBeta:
manager.opBeta = &computebeta.Operation{}
return manager.opBeta, nil
case targetAlpha:
manager.opAlpha = &computealpha.Operation{}
return manager.opAlpha, nil
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
/**
* Gets disk info stored in the FakeServiceManager.
*/
func (manager *FakeServiceManager) GetDisk(
zone string, diskName string) (*GCEDisk, error) {
if manager.zonalDisks[zone] == "" {
return nil, cloudprovider.DiskNotFound
}
if manager.resourceInUse {
errorItem := googleapi.ErrorItem{Reason: "resourceInUseByAnotherResource"}
err := &googleapi.Error{Errors: []googleapi.ErrorItem{errorItem}}
return nil, err
}
return &GCEDisk{
Region: manager.gceRegion,
ZoneInfo: singleZone{lastComponent(zone)},
Name: diskName,
Kind: "compute#disk",
Type: "type",
}, nil
}
/**
* Gets disk info stored in the FakeServiceManager.
*/
func (manager *FakeServiceManager) GetRegionalDisk(
diskName string) (*GCEDisk, error) {
if _, ok := manager.regionalDisks[diskName]; !ok {
return nil, cloudprovider.DiskNotFound
}
if manager.resourceInUse {
errorItem := googleapi.ErrorItem{Reason: "resourceInUseByAnotherResource"}
err := &googleapi.Error{Errors: []googleapi.ErrorItem{errorItem}}
return nil, err
}
return &GCEDisk{
Region: manager.gceRegion,
ZoneInfo: multiZone{manager.regionalDisks[diskName]},
Name: diskName,
Kind: "compute#disk",
Type: "type",
}, nil
}
/**
* Disk info is removed from the FakeServiceManager.
*/
func (manager *FakeServiceManager) DeleteDisk(
zone string,
disk string) (gceObject, error) {
manager.deleteDiskCalled = true
delete(manager.zonalDisks, zone)
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
return manager.opStable, nil
case targetBeta:
manager.opBeta = &computebeta.Operation{}
return manager.opBeta, nil
case targetAlpha:
manager.opAlpha = &computealpha.Operation{}
return manager.opAlpha, nil
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
func (manager *FakeServiceManager) DeleteRegionalDisk(
disk string) (gceObject, error) {
manager.deleteDiskCalled = true
delete(manager.regionalDisks, disk)
switch t := manager.targetAPI; t {
case targetStable:
manager.opStable = &compute.Operation{}
return manager.opStable, nil
case targetBeta:
manager.opBeta = &computebeta.Operation{}
return manager.opBeta, nil
case targetAlpha:
manager.opAlpha = &computealpha.Operation{}
return manager.opAlpha, nil
default:
return nil, fmt.Errorf("unexpected type: %T", t)
}
}
func (manager *FakeServiceManager) WaitForZoneOp(
op gceObject,
zone string,
mc *metricContext) error {
switch v := op.(type) {
case *computealpha.Operation:
if op.(*computealpha.Operation) == manager.opAlpha {
manager.doesOpMatch = true
}
case *computebeta.Operation:
if op.(*computebeta.Operation) == manager.opBeta {
manager.doesOpMatch = true
}
case *compute.Operation:
if op.(*compute.Operation) == manager.opStable {
manager.doesOpMatch = true
}
default:
return fmt.Errorf("unexpected type: %T", v)
}
return manager.waitForOpError
}
func (manager *FakeServiceManager) WaitForRegionalOp(
op gceObject, mc *metricContext) error {
switch v := op.(type) {
case *computealpha.Operation:
if op.(*computealpha.Operation) == manager.opAlpha {
manager.doesOpMatch = true
}
case *computebeta.Operation:
if op.(*computebeta.Operation) == manager.opBeta {
manager.doesOpMatch = true
}
case *compute.Operation:
if op.(*compute.Operation) == manager.opStable {
manager.doesOpMatch = true
}
default:
return fmt.Errorf("unexpected type: %T", v)
}
return manager.waitForOpError
}

View file

@ -0,0 +1,124 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"testing"
"k8s.io/api/core/v1"
)
func TestIsAtLeastMinNodesHealthCheckVersion(t *testing.T) {
testCases := []struct {
version string
expect bool
}{
{"v1.7.3", true},
{"v1.7.2", true},
{"v1.7.2-alpha.2.597+276d289b90d322", true},
{"v1.6.0-beta.3.472+831q821c907t31a", false},
{"v1.5.2", false},
}
for _, tc := range testCases {
if res := isAtLeastMinNodesHealthCheckVersion(tc.version); res != tc.expect {
t.Errorf("%v: want %v, got %v", tc.version, tc.expect, res)
}
}
}
func TestSupportsNodesHealthCheck(t *testing.T) {
testCases := []struct {
desc string
nodes []*v1.Node
expect bool
}{
{
"All nodes support nodes health check",
[]*v1.Node{
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.7.2",
},
},
},
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.7.2-alpha.2.597+276d289b90d322",
},
},
},
},
true,
},
{
"All nodes don't support nodes health check",
[]*v1.Node{
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.6.0-beta.3.472+831q821c907t31a",
},
},
},
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.5.2",
},
},
},
},
false,
},
{
"One node doesn't support nodes health check",
[]*v1.Node{
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.7.3",
},
},
},
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.7.2-alpha.2.597+276d289b90d322",
},
},
},
{
Status: v1.NodeStatus{
NodeInfo: v1.NodeSystemInfo{
KubeProxyVersion: "v1.5.2",
},
},
},
},
false,
},
}
for _, tc := range testCases {
if res := supportsNodesHealthCheck(tc.nodes); res != tc.expect {
t.Errorf("%v: want %v, got %v", tc.desc, tc.expect, res)
}
}
}

View file

@ -0,0 +1,239 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
computealpha "google.golang.org/api/compute/v0.alpha"
"k8s.io/api/core/v1"
)
func TestEnsureStaticIP(t *testing.T) {
fcas := NewFakeCloudAddressService()
ipName := "some-static-ip"
serviceName := ""
region := "us-central1"
// First ensure call
ip, existed, err := ensureStaticIP(fcas, ipName, serviceName, region, "", NetworkTierDefault)
if err != nil || existed || ip == "" {
t.Fatalf(`ensureStaticIP(%v, %v, %v, %v, "") = %v, %v, %v; want valid ip, false, nil`, fcas, ipName, serviceName, region, ip, existed, err)
}
// Second ensure call
var ipPrime string
ipPrime, existed, err = ensureStaticIP(fcas, ipName, serviceName, region, ip, NetworkTierDefault)
if err != nil || !existed || ip != ipPrime {
t.Fatalf(`ensureStaticIP(%v, %v, %v, %v, %v) = %v, %v, %v; want %v, true, nil`, fcas, ipName, serviceName, region, ip, ipPrime, existed, err, ip)
}
}
func TestEnsureStaticIPWithTier(t *testing.T) {
s := NewFakeCloudAddressService()
serviceName := ""
region := "us-east1"
for desc, tc := range map[string]struct {
name string
netTier NetworkTier
expected string
}{
"Premium (default)": {
name: "foo-1",
netTier: NetworkTierPremium,
expected: "PREMIUM",
},
"Standard": {
name: "foo-2",
netTier: NetworkTierStandard,
expected: "STANDARD",
},
} {
t.Run(desc, func(t *testing.T) {
ip, existed, err := ensureStaticIP(s, tc.name, serviceName, region, "", tc.netTier)
assert.NoError(t, err)
assert.False(t, existed)
assert.NotEqual(t, "", ip)
// Get the Address from the fake address service and verify that the tier
// is set correctly.
alphaAddr, err := s.GetAlphaRegionAddress(tc.name, region)
require.NoError(t, err)
assert.Equal(t, tc.expected, alphaAddr.NetworkTier)
})
}
}
func TestVerifyRequestedIP(t *testing.T) {
region := "test-region"
lbRef := "test-lb"
s := NewFakeCloudAddressService()
for desc, tc := range map[string]struct {
requestedIP string
fwdRuleIP string
netTier NetworkTier
addrList []*computealpha.Address
expectErr bool
expectUserOwned bool
}{
"requested IP exists": {
requestedIP: "1.1.1.1",
netTier: NetworkTierPremium,
addrList: []*computealpha.Address{{Name: "foo", Address: "1.1.1.1", NetworkTier: "PREMIUM"}},
expectErr: false,
expectUserOwned: true,
},
"requested IP is not static, but is in use by the fwd rule": {
requestedIP: "1.1.1.1",
fwdRuleIP: "1.1.1.1",
netTier: NetworkTierPremium,
expectErr: false,
},
"requested IP is not static and is not used by the fwd rule": {
requestedIP: "1.1.1.1",
fwdRuleIP: "2.2.2.2",
netTier: NetworkTierPremium,
expectErr: true,
},
"no requested IP": {
netTier: NetworkTierPremium,
expectErr: false,
},
"requested IP exists, but network tier does not match": {
requestedIP: "1.1.1.1",
netTier: NetworkTierStandard,
addrList: []*computealpha.Address{{Name: "foo", Address: "1.1.1.1", NetworkTier: "PREMIUM"}},
expectErr: true,
},
} {
t.Run(desc, func(t *testing.T) {
s.SetRegionalAddresses(region, tc.addrList)
isUserOwnedIP, err := verifyUserRequestedIP(s, region, tc.requestedIP, tc.fwdRuleIP, lbRef, tc.netTier)
assert.Equal(t, tc.expectErr, err != nil, fmt.Sprintf("err: %v", err))
assert.Equal(t, tc.expectUserOwned, isUserOwnedIP)
})
}
}
func TestCreateForwardingRuleWithTier(t *testing.T) {
s := NewFakeCloudForwardingRuleService()
// Common variables among the tests.
ports := []v1.ServicePort{{Name: "foo", Protocol: v1.ProtocolTCP, Port: int32(123)}}
region := "test-region"
target := "test-target-pool"
svcName := "foo-svc"
for desc, tc := range map[string]struct {
netTier NetworkTier
expectedRule *computealpha.ForwardingRule
}{
"Premium tier": {
netTier: NetworkTierPremium,
expectedRule: &computealpha.ForwardingRule{
Name: "lb-1",
Description: `{"kubernetes.io/service-name":"foo-svc"}`,
IPAddress: "1.1.1.1",
IPProtocol: "TCP",
PortRange: "123-123",
Target: target,
NetworkTier: "PREMIUM",
},
},
"Standard tier": {
netTier: NetworkTierStandard,
expectedRule: &computealpha.ForwardingRule{
Name: "lb-2",
Description: `{"kubernetes.io/service-name":"foo-svc"}`,
IPAddress: "2.2.2.2",
IPProtocol: "TCP",
PortRange: "123-123",
Target: target,
NetworkTier: "STANDARD",
},
},
} {
t.Run(desc, func(t *testing.T) {
lbName := tc.expectedRule.Name
ipAddr := tc.expectedRule.IPAddress
err := createForwardingRule(s, lbName, svcName, region, ipAddr, target, ports, tc.netTier)
assert.NoError(t, err)
alphaRule, err := s.GetAlphaRegionForwardingRule(lbName, region)
assert.NoError(t, err)
assert.Equal(t, tc.expectedRule, alphaRule)
})
}
}
func TestDeleteAddressWithWrongTier(t *testing.T) {
region := "test-region"
lbRef := "test-lb"
s := NewFakeCloudAddressService()
for desc, tc := range map[string]struct {
addrName string
netTier NetworkTier
addrList []*computealpha.Address
expectDelete bool
}{
"Network tiers (premium) match; do nothing": {
addrName: "foo1",
netTier: NetworkTierPremium,
addrList: []*computealpha.Address{{Name: "foo1", Address: "1.1.1.1", NetworkTier: "PREMIUM"}},
},
"Network tiers (standard) match; do nothing": {
addrName: "foo2",
netTier: NetworkTierStandard,
addrList: []*computealpha.Address{{Name: "foo2", Address: "1.1.1.2", NetworkTier: "STANDARD"}},
},
"Wrong network tier (standard); delete address": {
addrName: "foo3",
netTier: NetworkTierPremium,
addrList: []*computealpha.Address{{Name: "foo3", Address: "1.1.1.3", NetworkTier: "STANDARD"}},
expectDelete: true,
},
"Wrong network tier (preimium); delete address": {
addrName: "foo4",
netTier: NetworkTierStandard,
addrList: []*computealpha.Address{{Name: "foo4", Address: "1.1.1.4", NetworkTier: "PREMIUM"}},
expectDelete: true,
},
} {
t.Run(desc, func(t *testing.T) {
s.SetRegionalAddresses(region, tc.addrList)
// Sanity check to ensure we inject the right address.
_, err := s.GetRegionAddress(tc.addrName, region)
require.NoError(t, err)
err = deleteAddressWithWrongTier(s, region, tc.addrName, lbRef, tc.netTier)
assert.NoError(t, err)
// Check whether the address still exists.
_, err = s.GetRegionAddress(tc.addrName, region)
if tc.expectDelete {
assert.True(t, isNotFound(err))
} else {
assert.NoError(t, err)
}
})
}
}

View file

@ -0,0 +1,628 @@
/*
Copyright 2014 The Kubernetes Authors.
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 gce
import (
"encoding/json"
"reflect"
"strings"
"testing"
"golang.org/x/oauth2/google"
computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta"
computev1 "google.golang.org/api/compute/v1"
"k8s.io/kubernetes/pkg/cloudprovider"
)
func TestReadConfigFile(t *testing.T) {
const s = `[Global]
token-url = my-token-url
token-body = my-token-body
project-id = my-project
network-project-id = my-network-project
network-name = my-network
subnetwork-name = my-subnetwork
secondary-range-name = my-secondary-range
node-tags = my-node-tag1
node-instance-prefix = my-prefix
multizone = true
`
reader := strings.NewReader(s)
config, err := readConfig(reader)
if err != nil {
t.Fatalf("Unexpected config parsing error %v", err)
}
expected := &ConfigFile{Global: ConfigGlobal{
TokenURL: "my-token-url",
TokenBody: "my-token-body",
ProjectID: "my-project",
NetworkProjectID: "my-network-project",
NetworkName: "my-network",
SubnetworkName: "my-subnetwork",
SecondaryRangeName: "my-secondary-range",
NodeTags: []string{"my-node-tag1"},
NodeInstancePrefix: "my-prefix",
Multizone: true,
}}
if !reflect.DeepEqual(expected, config) {
t.Fatalf("Expected config file values to be read into ConfigFile struct. \nExpected:\n%+v\nActual:\n%+v", expected, config)
}
}
func TestExtraKeyInConfig(t *testing.T) {
const s = `[Global]
project-id = my-project
unknown-key = abc
network-name = my-network
`
reader := strings.NewReader(s)
config, err := readConfig(reader)
if err != nil {
t.Fatalf("Unexpected config parsing error %v", err)
}
if config.Global.ProjectID != "my-project" || config.Global.NetworkName != "my-network" {
t.Fatalf("Expected config values to continue to be read despite extra key-value pair.")
}
}
func TestGetRegion(t *testing.T) {
zoneName := "us-central1-b"
regionName, err := GetGCERegion(zoneName)
if err != nil {
t.Fatalf("unexpected error from GetGCERegion: %v", err)
}
if regionName != "us-central1" {
t.Errorf("Unexpected region from GetGCERegion: %s", regionName)
}
gce := &GCECloud{
localZone: zoneName,
region: regionName,
}
zones, ok := gce.Zones()
if !ok {
t.Fatalf("Unexpected missing zones impl")
}
zone, err := zones.GetZone()
if err != nil {
t.Fatalf("unexpected error %v", err)
}
if zone.Region != "us-central1" {
t.Errorf("Unexpected region: %s", zone.Region)
}
}
func TestComparingHostURLs(t *testing.T) {
tests := []struct {
host1 string
zone string
name string
expectEqual bool
}{
{
host1: "https://www.googleapis.com/compute/v1/projects/1234567/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-f",
name: "kubernetes-node-fhx1",
expectEqual: true,
},
{
host1: "https://www.googleapis.com/compute/v1/projects/cool-project/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-f",
name: "kubernetes-node-fhx1",
expectEqual: true,
},
{
host1: "https://www.googleapis.com/compute/v23/projects/1234567/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-f",
name: "kubernetes-node-fhx1",
expectEqual: true,
},
{
host1: "https://www.googleapis.com/compute/v24/projects/1234567/regions/us-central1/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-f",
name: "kubernetes-node-fhx1",
expectEqual: true,
},
{
host1: "https://www.googleapis.com/compute/v1/projects/1234567/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-c",
name: "kubernetes-node-fhx1",
expectEqual: false,
},
{
host1: "https://www.googleapis.com/compute/v1/projects/1234567/zones/us-central1-f/instances/kubernetes-node-fhx",
zone: "us-central1-f",
name: "kubernetes-node-fhx1",
expectEqual: false,
},
{
host1: "https://www.googleapis.com/compute/v1/projects/1234567/zones/us-central1-f/instances/kubernetes-node-fhx1",
zone: "us-central1-f",
name: "kubernetes-node-fhx",
expectEqual: false,
},
}
for _, test := range tests {
link1 := hostURLToComparablePath(test.host1)
testInstance := &gceInstance{
Name: canonicalizeInstanceName(test.name),
Zone: test.zone,
}
link2 := testInstance.makeComparableHostPath()
if test.expectEqual && link1 != link2 {
t.Errorf("expected link1 and link2 to be equal, got %s and %s", link1, link2)
} else if !test.expectEqual && link1 == link2 {
t.Errorf("expected link1 and link2 not to be equal, got %s and %s", link1, link2)
}
}
}
func TestScrubDNS(t *testing.T) {
tcs := []struct {
nameserversIn []string
searchesIn []string
nameserversOut []string
searchesOut []string
}{
{
nameserversIn: []string{"1.2.3.4", "5.6.7.8"},
nameserversOut: []string{"1.2.3.4", "5.6.7.8"},
},
{
searchesIn: []string{"c.prj.internal.", "12345678910.google.internal.", "google.internal."},
searchesOut: []string{"c.prj.internal.", "google.internal."},
},
{
searchesIn: []string{"c.prj.internal.", "12345678910.google.internal.", "zone.c.prj.internal.", "google.internal."},
searchesOut: []string{"c.prj.internal.", "zone.c.prj.internal.", "google.internal."},
},
{
searchesIn: []string{"c.prj.internal.", "12345678910.google.internal.", "zone.c.prj.internal.", "google.internal.", "unexpected"},
searchesOut: []string{"c.prj.internal.", "zone.c.prj.internal.", "google.internal.", "unexpected"},
},
}
gce := &GCECloud{}
for i := range tcs {
n, s := gce.ScrubDNS(tcs[i].nameserversIn, tcs[i].searchesIn)
if !reflect.DeepEqual(n, tcs[i].nameserversOut) {
t.Errorf("Expected %v, got %v", tcs[i].nameserversOut, n)
}
if !reflect.DeepEqual(s, tcs[i].searchesOut) {
t.Errorf("Expected %v, got %v", tcs[i].searchesOut, s)
}
}
}
func TestSplitProviderID(t *testing.T) {
providers := []struct {
providerID string
project string
zone string
instance string
fail bool
}{
{
providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1",
project: "project-example-164317",
zone: "us-central1-f",
instance: "kubernetes-node-fhx1",
fail: false,
},
{
providerID: ProviderName + "://project-example.164317/us-central1-f/kubernetes-node-fhx1",
project: "project-example.164317",
zone: "us-central1-f",
instance: "kubernetes-node-fhx1",
fail: false,
},
{
providerID: ProviderName + "://project-example-164317/us-central1-fkubernetes-node-fhx1",
project: "",
zone: "",
instance: "",
fail: true,
},
{
providerID: ProviderName + ":/project-example-164317/us-central1-f/kubernetes-node-fhx1",
project: "",
zone: "",
instance: "",
fail: true,
},
{
providerID: "aws://project-example-164317/us-central1-f/kubernetes-node-fhx1",
project: "",
zone: "",
instance: "",
fail: true,
},
{
providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1/",
project: "",
zone: "",
instance: "",
fail: true,
},
{
providerID: ProviderName + "://project-example.164317//kubernetes-node-fhx1",
project: "",
zone: "",
instance: "",
fail: true,
},
{
providerID: ProviderName + "://project-example.164317/kubernetes-node-fhx1",
project: "",
zone: "",
instance: "",
fail: true,
},
}
for _, test := range providers {
project, zone, instance, err := splitProviderID(test.providerID)
if (err != nil) != test.fail {
t.Errorf("Expected to fail=%t, with pattern %v", test.fail, test)
}
if test.fail {
continue
}
if project != test.project {
t.Errorf("Expected %v, but got %v", test.project, project)
}
if zone != test.zone {
t.Errorf("Expected %v, but got %v", test.zone, zone)
}
if instance != test.instance {
t.Errorf("Expected %v, but got %v", test.instance, instance)
}
}
}
func TestGetZoneByProviderID(t *testing.T) {
tests := []struct {
providerID string
expectedZone cloudprovider.Zone
fail bool
description string
}{
{
providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1",
expectedZone: cloudprovider.Zone{FailureDomain: "us-central1-f", Region: "us-central1"},
fail: false,
description: "standard gce providerID",
},
{
providerID: ProviderName + "://project-example-164317/us-central1-f/kubernetes-node-fhx1/",
expectedZone: cloudprovider.Zone{},
fail: true,
description: "too many slashes('/') trailing",
},
{
providerID: ProviderName + "://project-example.164317//kubernetes-node-fhx1",
expectedZone: cloudprovider.Zone{},
fail: true,
description: "too many slashes('/') embedded",
},
{
providerID: ProviderName + "://project-example-164317/uscentral1f/kubernetes-node-fhx1",
expectedZone: cloudprovider.Zone{},
fail: true,
description: "invalid name of the GCE zone",
},
}
gce := &GCECloud{
localZone: "us-central1-f",
region: "us-central1",
}
for _, test := range tests {
zone, err := gce.GetZoneByProviderID(test.providerID)
if (err != nil) != test.fail {
t.Errorf("Expected to fail=%t, provider ID %v, tests %s", test.fail, test, test.description)
}
if test.fail {
continue
}
if zone != test.expectedZone {
t.Errorf("Expected %v, but got %v", test.expectedZone, zone)
}
}
}
func TestGenerateCloudConfigs(t *testing.T) {
configBoilerplate := ConfigGlobal{
TokenURL: "",
TokenBody: "",
ProjectID: "project-id",
NetworkName: "network-name",
SubnetworkName: "",
SecondaryRangeName: "",
NodeTags: []string{"node-tag"},
NodeInstancePrefix: "node-prefix",
Multizone: false,
ApiEndpoint: "",
LocalZone: "us-central1-a",
AlphaFeatures: []string{},
}
cloudBoilerplate := CloudConfig{
ApiEndpoint: "",
ProjectID: "project-id",
NetworkProjectID: "",
Region: "us-central1",
Zone: "us-central1-a",
ManagedZones: []string{"us-central1-a"},
NetworkName: "network-name",
SubnetworkName: "",
NetworkURL: "",
SubnetworkURL: "",
SecondaryRangeName: "",
NodeTags: []string{"node-tag"},
TokenSource: google.ComputeTokenSource(""),
NodeInstancePrefix: "node-prefix",
UseMetadataServer: true,
AlphaFeatureGate: &AlphaFeatureGate{map[string]bool{}},
}
testCases := []struct {
name string
config func() ConfigGlobal
cloud func() CloudConfig
}{
{
name: "Empty Config",
config: func() ConfigGlobal { return configBoilerplate },
cloud: func() CloudConfig { return cloudBoilerplate },
},
{
name: "Nil token URL",
config: func() ConfigGlobal {
v := configBoilerplate
v.TokenURL = "nil"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.TokenSource = nil
return v
},
},
{
name: "Network Project ID",
config: func() ConfigGlobal {
v := configBoilerplate
v.NetworkProjectID = "my-awesome-project"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.NetworkProjectID = "my-awesome-project"
return v
},
},
{
name: "Specified API Endpint",
config: func() ConfigGlobal {
v := configBoilerplate
v.ApiEndpoint = "https://www.googleapis.com/compute/staging_v1/"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.ApiEndpoint = "https://www.googleapis.com/compute/staging_v1/"
return v
},
},
{
name: "Network & Subnetwork names",
config: func() ConfigGlobal {
v := configBoilerplate
v.NetworkName = "my-network"
v.SubnetworkName = "my-subnetwork"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.NetworkName = "my-network"
v.SubnetworkName = "my-subnetwork"
return v
},
},
{
name: "Network & Subnetwork URLs",
config: func() ConfigGlobal {
v := configBoilerplate
v.NetworkName = "https://www.googleapis.com/compute/v1/projects/project-id/global/networks/my-network"
v.SubnetworkName = "https://www.googleapis.com/compute/v1/projects/project-id/regions/us-central1/subnetworks/my-subnetwork"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.NetworkName = ""
v.SubnetworkName = ""
v.NetworkURL = "https://www.googleapis.com/compute/v1/projects/project-id/global/networks/my-network"
v.SubnetworkURL = "https://www.googleapis.com/compute/v1/projects/project-id/regions/us-central1/subnetworks/my-subnetwork"
return v
},
},
{
name: "Multizone",
config: func() ConfigGlobal {
v := configBoilerplate
v.Multizone = true
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.ManagedZones = nil
return v
},
},
{
name: "Secondary Range Name",
config: func() ConfigGlobal {
v := configBoilerplate
v.SecondaryRangeName = "my-secondary"
return v
},
cloud: func() CloudConfig {
v := cloudBoilerplate
v.SecondaryRangeName = "my-secondary"
return v
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resultCloud, err := generateCloudConfig(&ConfigFile{Global: tc.config()})
if err != nil {
t.Fatalf("Unexpect error: %v", err)
}
v := tc.cloud()
if !reflect.DeepEqual(*resultCloud, v) {
t.Errorf("Got: \n%v\nWant\n%v\n", v, *resultCloud)
}
})
}
}
func TestConvertToV1Operation(t *testing.T) {
v1Op := getTestOperation()
enc, _ := v1Op.MarshalJSON()
var op interface{}
var alphaOp computealpha.Operation
var betaOp computebeta.Operation
if err := json.Unmarshal(enc, &alphaOp); err != nil {
t.Errorf("Failed to unmarshal operation: %v", err)
}
if err := json.Unmarshal(enc, &betaOp); err != nil {
t.Errorf("Failed to unmarshal operation: %v", err)
}
op = convertToV1Operation(&alphaOp)
if _, ok := op.(*computev1.Operation); ok {
if !reflect.DeepEqual(op, v1Op) {
t.Errorf("Failed to maintain consistency across conversion")
}
} else {
t.Errorf("Expect output to be type v1 operation, but got %v", op)
}
op = convertToV1Operation(&betaOp)
if _, ok := op.(*computev1.Operation); ok {
if !reflect.DeepEqual(op, v1Op) {
t.Errorf("Failed to maintain consistency across conversion")
}
} else {
t.Errorf("Expect output to be type v1 operation, but got %v", op)
}
}
func getTestOperation() *computev1.Operation {
return &computev1.Operation{
Name: "test",
Description: "test",
Id: uint64(12345),
Error: &computev1.OperationError{
Errors: []*computev1.OperationErrorErrors{
{
Code: "555",
Message: "error",
},
},
},
}
}
func TestNewAlphaFeatureGate(t *testing.T) {
knownAlphaFeatures["foo"] = true
knownAlphaFeatures["bar"] = true
testCases := []struct {
alphaFeatures []string
expectEnabled []string
expectDisabled []string
expectError bool
}{
// enable foo bar
{
alphaFeatures: []string{"foo", "bar"},
expectEnabled: []string{"foo", "bar"},
expectDisabled: []string{"aaa"},
expectError: false,
},
// no alpha feature
{
alphaFeatures: []string{},
expectEnabled: []string{},
expectDisabled: []string{"foo", "bar"},
expectError: false,
},
// unsupported alpha feature
{
alphaFeatures: []string{"aaa", "foo"},
expectError: true,
expectEnabled: []string{"foo"},
expectDisabled: []string{"aaa"},
},
// enable foo
{
alphaFeatures: []string{"foo"},
expectEnabled: []string{"foo"},
expectDisabled: []string{"bar"},
expectError: false,
},
}
for _, tc := range testCases {
featureGate, err := NewAlphaFeatureGate(tc.alphaFeatures)
if (tc.expectError && err == nil) || (!tc.expectError && err != nil) {
t.Errorf("Expect error to be %v, but got error %v", tc.expectError, err)
}
for _, key := range tc.expectEnabled {
if !featureGate.Enabled(key) {
t.Errorf("Expect %q to be enabled.", key)
}
}
for _, key := range tc.expectDisabled {
if featureGate.Enabled(key) {
t.Errorf("Expect %q to be disabled.", key)
}
}
}
delete(knownAlphaFeatures, "foo")
delete(knownAlphaFeatures, "bar")
}

View file

@ -0,0 +1,28 @@
/*
Copyright 2017 The Kubernetes Authors.
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 gce
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestVerifyMetricLabelCardinality(t *testing.T) {
mc := newGenericMetricContext("foo", "get", "us-central1", "<n/a>", "alpha")
assert.Len(t, mc.attributes, len(metricLabels), "cardinalities of labels and values must match")
}