Unified Storage: Return an already exists error (#102857)

* Unified Storage: Return an already exists error

When inserting a resource that already exists (i.e. race condition), we can safely catch UNIQUE constraint violations
and transform them into a `k8s.io/apimachinery/pkg/api/errors` error that stands the test of `errors.IsAlreadyExists`.

* feat: clarify existing conflict error

* chore: make update-workspace

* feat: make new package for backend error

* fix: assign dependency owner

* feat: use dialect for checking error type

* chore: go generate

* revert: to 5af369166d6
This commit is contained in:
Mariell Hoversholm
2025-03-26 14:44:44 +01:00
committed by GitHub
parent 9f7df8b788
commit f7b9f1ce69
6 changed files with 91 additions and 1 deletions

View File

@ -8,10 +8,12 @@ import (
"testing"
sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/grafana/grafana/pkg/apimachinery/utils"
unifiedbackend "github.com/grafana/grafana/pkg/storage/unified/backend"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/storage/unified/sql/db/dbimpl"
"github.com/grafana/grafana/pkg/storage/unified/sql/test"
@ -229,6 +231,29 @@ func TestBackend_create(t *testing.T) {
require.Equal(t, int64(200), v)
})
t.Run("resource already exists", func(t *testing.T) {
t.Parallel()
b, ctx := setupBackendTest(t)
b.SQLMock.ExpectBegin()
expectSuccessfulResourceVersionExec(t, b.TestDBProvider,
func() { b.ExecWithResult("insert resource", 0, 1) },
func() { b.ExecWithResult("insert resource_history", 0, 1) },
)
b.SQLMock.ExpectCommit()
b.SQLMock.ExpectBegin()
b.SQLMock.ExpectExec("insert resource").WillReturnError(sqlite3.Error{Code: sqlite3.ErrConstraint, ExtendedCode: sqlite3.ErrConstraintUnique})
b.SQLMock.ExpectRollback()
// First we insert the resource successfully. This is what the happy path test does as well.
v, err := b.create(ctx, event)
require.NoError(t, err)
require.Equal(t, int64(200), v)
// Then we try to insert the same resource again. This should fail.
_, err = b.create(ctx, event)
require.ErrorIs(t, err, unifiedbackend.ErrResourceAlreadyExists)
})
t.Run("error inserting into resource", func(t *testing.T) {
t.Parallel()
b, ctx := setupBackendTest(t)