mirror of
https://github.com/actions-runner-controller/actions-runner-controller.git
synced 2026-09-30 13:32:54 +02:00
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
114 lines
3.7 KiB
Go
114 lines
3.7 KiB
Go
package actionsgithubcom
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
)
|
|
|
|
func TestLazyCopyDoesNotCopyUntilMutated(t *testing.T) {
|
|
pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod"}}
|
|
lazy := newLazyCopy(pod)
|
|
|
|
assert.False(t, lazy.Modified())
|
|
assert.Panics(t, func() { lazy.MergeFrom() })
|
|
}
|
|
|
|
func TestLazyCopySnapshotsBeforeTheFirstMutation(t *testing.T) {
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod",
|
|
Annotations: map[string]string{"key": "old"},
|
|
},
|
|
}
|
|
lazy := newLazyCopy(pod)
|
|
|
|
lazy.Mutate().Annotations["key"] = "new"
|
|
require.True(t, lazy.Modified())
|
|
|
|
data, err := lazy.MergeFrom().Data(pod)
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, `{"metadata":{"annotations":{"key":"new"}}}`, string(data))
|
|
}
|
|
|
|
func TestLazyCopySnapshotsOnlyOnce(t *testing.T) {
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod",
|
|
Annotations: map[string]string{"first": "old", "second": "old"},
|
|
},
|
|
}
|
|
lazy := newLazyCopy(pod)
|
|
|
|
lazy.Mutate().Annotations["first"] = "new"
|
|
// The second mutation must diff against the state before the first one,
|
|
// otherwise the earlier change is dropped from the patch.
|
|
lazy.Mutate().Annotations["second"] = "new"
|
|
|
|
data, err := lazy.MergeFrom().Data(pod)
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, `{"metadata":{"annotations":{"first":"new","second":"new"}}}`, string(data))
|
|
}
|
|
|
|
func TestLazyCopyMergeFromIsAMergePatch(t *testing.T) {
|
|
pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod"}}
|
|
lazy := newLazyCopy(pod)
|
|
lazy.Mutate().Labels = map[string]string{"key": "value"}
|
|
|
|
assert.Equal(t, client.MergeFrom(pod).Type(), lazy.MergeFrom().Type())
|
|
}
|
|
|
|
// Pins the hazard documented on lazyCopy: the caller keeps the pointer it
|
|
// handed to newLazyCopy, so it can write through it without going via Mutate.
|
|
// A write that lands before the first Mutate is already in the snapshot, so it
|
|
// is absent from the patch and never reaches the API server. The type cannot
|
|
// prevent this, which is why the ordering is a caller invariant rather than a
|
|
// guarantee.
|
|
func TestLazyCopyDropsWritesMadeBeforeTheFirstMutate(t *testing.T) {
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod",
|
|
Annotations: map[string]string{"smuggled": "old", "declared": "old"},
|
|
},
|
|
}
|
|
lazy := newLazyCopy(pod)
|
|
|
|
// Bypasses Mutate, so it is captured by the snapshot taken below.
|
|
pod.Annotations["smuggled"] = "new"
|
|
|
|
lazy.Mutate().Annotations["declared"] = "new"
|
|
|
|
data, err := lazy.MergeFrom().Data(pod)
|
|
require.NoError(t, err)
|
|
assert.JSONEq(t, `{"metadata":{"annotations":{"declared":"new"}}}`, string(data))
|
|
}
|
|
|
|
// The status patch in patchAppliedActionableRevisionStatus relies on being able
|
|
// to attach an optimistic lock, so that a patch computed from a stale read is
|
|
// rejected by the API server rather than silently moving the applied revision
|
|
// backwards. Without the precondition the patch can never conflict, so the
|
|
// surrounding RetryOnConflict would never fire.
|
|
func TestLazyCopyMergeFromForwardsMergeOptions(t *testing.T) {
|
|
pod := &corev1.Pod{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "pod",
|
|
ResourceVersion: "42",
|
|
},
|
|
}
|
|
lazy := newLazyCopy(pod)
|
|
lazy.Mutate().Labels = map[string]string{"key": "value"}
|
|
|
|
data, err := lazy.MergeFrom(client.MergeFromWithOptimisticLock{}).Data(pod)
|
|
require.NoError(t, err)
|
|
assert.JSONEq(
|
|
t,
|
|
`{"metadata":{"labels":{"key":"value"},"resourceVersion":"42"}}`,
|
|
string(data),
|
|
"the lock is carried as a resourceVersion precondition in the patch body, taken from the snapshot rather than the mutated object",
|
|
)
|
|
}
|