mirror of
https://github.com/gitpod-io/gitpod.git
synced 2025-12-08 17:36:30 +00:00
223 lines
5.4 KiB
Go
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)
|
|
}
|
|
})
|
|
}
|
|
}
|