2022-02-22 16:25:02 +05:30

223 lines
5.4 KiB
Go

// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License-AGPL.txt in the project root for license information.
package manager
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
ctesting "github.com/gitpod-io/gitpod/common-go/testing"
"github.com/gitpod-io/gitpod/common-go/util"
"github.com/gitpod-io/gitpod/ws-manager/api"
config "github.com/gitpod-io/gitpod/ws-manager/api/config"
"github.com/gitpod-io/gitpod/ws-manager/pkg/clock"
"github.com/google/go-cmp/cmp"
)
func TestIsWorkspaceTimedout(t *testing.T) {
type fixture struct {
Activity string `json:"activity,omitempty"`
WSO workspaceObjects `json:"wso"`
CreationDelta string `json:"creationDelta,omitempty"`
StoppingSinceDelta string `json:"stoppingSinceDelta,omitempty"`
}
type gold struct {
Reason string `json:"reason,omitempty"`
Error string `json:"error,omitempty"`
}
test := ctesting.FixtureTest{
T: t,
Path: "testdata/timeout*.json",
Test: func(t *testing.T, input interface{}) interface{} {
fixture := input.(*fixture)
manager := Manager{
clock: clock.LogicalOnly(),
Config: config.Configuration{
Timeouts: config.WorkspaceTimeoutConfiguration{
AfterClose: util.Duration(1 * time.Minute),
Initialization: util.Duration(30 * time.Minute),
TotalStartup: util.Duration(45 * time.Minute),
RegularWorkspace: util.Duration(60 * time.Minute),
MaxLifetime: util.Duration(36 * time.Hour),
HeadlessWorkspace: util.Duration(90 * time.Minute),
Stopping: util.Duration(60 * time.Minute),
ContentFinalization: util.Duration(55 * time.Minute),
Interrupted: util.Duration(5 * time.Minute),
},
},
}
if fixture.Activity != "" {
dt, err := time.ParseDuration(fixture.Activity)
if err != nil {
t.Errorf("cannot parse fixture's Activity: %v", err)
return nil
}
workspaceID, ok := fixture.WSO.WorkspaceID()
if !ok {
t.Errorf("fixture pod has no %s annotation", workspaceIDAnnotation)
return nil
}
delta := time.Now().Add(-dt)
manager.activity.Store(workspaceID, &delta)
}
if fixture.CreationDelta != "" && fixture.WSO.Pod != nil {
dt, err := time.ParseDuration(fixture.CreationDelta)
if err != nil {
t.Errorf("cannot parse fixture's CreationDelta: %v", err)
return nil
}
fixture.WSO.Pod.ObjectMeta.CreationTimestamp = metav1.Time{Time: time.Now().Add(-dt)}
}
reason, serr := manager.isWorkspaceTimedOut(fixture.WSO)
result := gold{Reason: reason}
if serr != nil {
result.Error = serr.Error()
}
return &result
},
Fixture: func() interface{} { return &fixture{} },
Gold: func() interface{} { return &gold{} },
}
test.Run()
}
func TestGetWorkspaceStatusWithFixtures(t *testing.T) {
type statusTestResult struct {
Status *api.WorkspaceStatus `json:"status"`
Error string `json:"error,omitempty"`
}
test := ctesting.FixtureTest{
T: t,
Path: "testdata/status_*.json",
Test: func(t *testing.T, input interface{}) interface{} {
fixture := input.(*workspaceObjects)
manager := Manager{
clock: clock.LogicalOnly(),
}
status, serr := manager.getWorkspaceStatus(*fixture)
result := statusTestResult{Status: status}
if serr != nil {
result.Error = serr.Error()
}
return &result
},
Fixture: func() interface{} { return &workspaceObjects{} },
Gold: func() interface{} { return &statusTestResult{} },
}
test.Run()
}
func BenchmarkGetStatus(b *testing.B) {
fs, err := filepath.Glob("testdata/status_*.json")
if err != nil {
b.Fatal(err)
}
for _, f := range fs {
if strings.Contains(f, "degenerate") {
continue
}
b.Run(f, func(b *testing.B) {
b.ReportAllocs()
buf, err := os.ReadFile(f)
if err != nil {
b.Fatal(err)
}
var wso workspaceObjects
err = json.Unmarshal(buf, &wso)
if err != nil {
b.Fatal(err)
}
manager := Manager{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, err := manager.getWorkspaceStatus(wso)
if err != nil {
b.Fatal(err)
}
}
})
}
}
func TestGetNodeName(t *testing.T) {
tests := []struct {
Name string
WSO workspaceObjects
Expectation string
}{
{
Name: "no nodeName",
},
{
Name: "spec",
WSO: workspaceObjects{
Pod: &v1.Pod{
Spec: v1.PodSpec{
NodeName: "foobar",
},
},
},
Expectation: "foobar",
},
{
Name: "annotation",
WSO: workspaceObjects{
Pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
nodeNameAnnotation: "from-anno",
},
},
},
},
Expectation: "from-anno",
},
{
Name: "spec and annotation",
WSO: workspaceObjects{
Pod: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
nodeNameAnnotation: "from-anno",
},
},
Spec: v1.PodSpec{
NodeName: "from-spec",
},
},
},
Expectation: "from-spec",
},
}
for _, test := range tests {
t.Run(test.Name, func(t *testing.T) {
act := test.WSO.NodeName()
if diff := cmp.Diff(test.Expectation, act); diff != "" {
t.Errorf("unexpected nodeName (-want +got):\n%s", diff)
}
})
}
}