github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/debugging/container_manager_test.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package debugging
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/watch"
    26  
    27  	"github.com/GoogleContainerTools/skaffold/testutil"
    28  )
    29  
    30  func TestContainerManager(t *testing.T) {
    31  	makePod := func(name string, state v1.ContainerState) v1.Pod {
    32  		return v1.Pod{
    33  			ObjectMeta: metav1.ObjectMeta{
    34  				Name:        name,
    35  				Namespace:   "ns",
    36  				Annotations: map[string]string{"debug.cloud.google.com/config": `{"test":{"runtime":"jvm","debugPorts":{"jdwp":5005}}}`},
    37  			},
    38  			Spec: v1.PodSpec{Containers: []v1.Container{
    39  				{
    40  					Name:    "test",
    41  					Command: []string{"java", "-jar", "foo.jar"},
    42  					Env:     []v1.EnvVar{{Name: "JAVA_TOOL_OPTIONS", Value: "-agentlib:jdwp=transport=dt_socket,server=y,address=5005,suspend=n,quiet=y"}},
    43  					Ports:   []v1.ContainerPort{{Name: "jdwp", ContainerPort: 5005}},
    44  				}}},
    45  			Status: v1.PodStatus{ContainerStatuses: []v1.ContainerStatus{{Name: "test", State: state}}},
    46  		}
    47  	}
    48  
    49  	type podEvent struct {
    50  		eventType watch.EventType
    51  		pod       v1.Pod
    52  
    53  		wantActiveKeys      []string
    54  		wantStartCount      int
    55  		wantTerminatedCount int
    56  	}
    57  	tests := []struct {
    58  		description string
    59  		events      []podEvent
    60  	}{
    61  		{
    62  			description: "pod added, container started, and then terminates",
    63  			events: []podEvent{
    64  				{eventType: watch.Added, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    65  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    66  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 1, wantActiveKeys: []string{"ns/pod/test"}},
    67  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 1, wantActiveKeys: []string{"ns/pod/test"}},
    68  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 1, wantTerminatedCount: 1},
    69  				{eventType: watch.Deleted, pod: makePod("pod", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 1, wantTerminatedCount: 1},
    70  			},
    71  		},
    72  		{
    73  			description: "pod added, container started, and then deleted before termination",
    74  			events: []podEvent{
    75  				{eventType: watch.Added, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    76  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    77  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 1, wantActiveKeys: []string{"ns/pod/test"}},
    78  				{eventType: watch.Deleted, pod: makePod("pod", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 1, wantTerminatedCount: 1},
    79  			},
    80  		},
    81  		{
    82  			description: "pods added, container started, and terminated several times (like iterative debugging)",
    83  			events: []podEvent{
    84  				{eventType: watch.Added, pod: makePod("pod1", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    85  				{eventType: watch.Modified, pod: makePod("pod1", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    86  				{eventType: watch.Modified, pod: makePod("pod1", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 1, wantActiveKeys: []string{"ns/pod1/test"}},
    87  				{eventType: watch.Added, pod: makePod("pod2", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 1, wantActiveKeys: []string{"ns/pod1/test"}},
    88  				{eventType: watch.Modified, pod: makePod("pod2", v1.ContainerState{Running: &v1.ContainerStateRunning{}}), wantStartCount: 2, wantActiveKeys: []string{"ns/pod1/test", "ns/pod2/test"}},
    89  				{eventType: watch.Modified, pod: makePod("pod1", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 2, wantTerminatedCount: 1, wantActiveKeys: []string{"ns/pod2/test"}},
    90  				{eventType: watch.Deleted, pod: makePod("pod1", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 2, wantTerminatedCount: 1, wantActiveKeys: []string{"ns/pod2/test"}},
    91  				{eventType: watch.Deleted, pod: makePod("pod2", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 2, wantTerminatedCount: 2},
    92  			},
    93  		},
    94  		{
    95  			description: "pod added, container never started, and then deleted",
    96  			events: []podEvent{
    97  				{eventType: watch.Added, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    98  				{eventType: watch.Modified, pod: makePod("pod", v1.ContainerState{Waiting: &v1.ContainerStateWaiting{}}), wantStartCount: 0},
    99  				{eventType: watch.Deleted, pod: makePod("pod", v1.ContainerState{Terminated: &v1.ContainerStateTerminated{}}), wantStartCount: 0, wantTerminatedCount: 0},
   100  			},
   101  		},
   102  	}
   103  
   104  	for _, tc := range tests {
   105  		testutil.Run(t, tc.description, func(t *testutil.T) {
   106  			ev1StartCount, ev1TerminatedCount := 0, 0
   107  			ev2StartCount, ev2TerminatedCount := 0, 0
   108  			// Override event v1 funcs to do nothing to avoid additional overhead
   109  			t.Override(&notifyDebuggingContainerStarted, func(podName string, containerName string, namespace string, artifactImage string, runtime string, workingDir string, debugPorts map[string]uint32) {
   110  				ev1StartCount++
   111  			})
   112  			t.Override(&notifyDebuggingContainerTerminated, func(podName string, containerName string, namespace string, artifactImage string, runtime string, workingDir string, debugPorts map[string]uint32) {
   113  				ev1TerminatedCount++
   114  			})
   115  			t.Override(&debuggingContainerStartedV2, func(podName string, containerName string, namespace string, artifactImage string, runtime string, workingDir string, debugPorts map[string]uint32) {
   116  				ev2StartCount++
   117  			})
   118  			t.Override(&debuggingContainerTerminatedV2, func(podName string, containerName string, namespace string, artifactImage string, runtime string, workingDir string, debugPorts map[string]uint32) {
   119  				ev2TerminatedCount++
   120  			})
   121  
   122  			m := &ContainerManager{active: make(map[string]string)}
   123  
   124  			for i, event := range tc.events {
   125  				m.checkPod(event.eventType, &event.pod)
   126  				if len(event.wantActiveKeys) != len(m.active) {
   127  					t.Fatalf("step %d: active pod count: got=%d want=%d: active=%v", i, len(m.active), len(event.wantActiveKeys), m.active)
   128  				}
   129  				if event.wantStartCount != ev1StartCount {
   130  					t.Fatalf("step %d: v1 start count: got=%d want=%d", i, ev1StartCount, event.wantStartCount)
   131  				}
   132  				if event.wantTerminatedCount != ev1TerminatedCount {
   133  					t.Fatalf("step %d: v1 terminated count: got=%d want=%d", i, ev1TerminatedCount, event.wantTerminatedCount)
   134  				}
   135  				if event.wantStartCount != ev2StartCount {
   136  					t.Fatalf("step %d: v2 start count: got=%d want=%d", i, ev2StartCount, event.wantStartCount)
   137  				}
   138  				if event.wantTerminatedCount != ev2TerminatedCount {
   139  					t.Fatalf("step %d: v2 terminated count: got=%d want=%d", i, ev2TerminatedCount, event.wantTerminatedCount)
   140  				}
   141  				for _, key := range event.wantActiveKeys {
   142  					if _, found := m.active[key]; !found {
   143  						t.Fatalf("step %d: expected to find pod %q in active list: got=%v want=%v", i, key, m.active, event.wantActiveKeys)
   144  					}
   145  				}
   146  			}
   147  		})
   148  	}
   149  }
   150  
   151  func TestContainerManagerZeroValue(t *testing.T) {
   152  	var m *ContainerManager
   153  
   154  	// Should not raise a nil dereference
   155  	m.Start(context.Background())
   156  	m.Stop()
   157  }