//go:build integration // +build integration package sqlstore import ( "context" "testing" "time" "github.com/grafana/grafana/pkg/models" "github.com/stretchr/testify/assert" ) func TestApiKeyDataAccess(t *testing.T) { mockTimeNow() defer resetTimeNow() t.Run("Testing API Key data access", func(t *testing.T) { InitTestDB(t) t.Run("Given saved api key", func(t *testing.T) { cmd := models.AddApiKeyCommand{OrgId: 1, Name: "hello", Key: "asd"} err := AddApiKey(&cmd) assert.Nil(t, err) t.Run("Should be able to get key by name", func(t *testing.T) { query := models.GetApiKeyByNameQuery{KeyName: "hello", OrgId: 1} err = GetApiKeyByName(&query) assert.Nil(t, err) assert.NotNil(t, query.Result) }) }) t.Run("Add non expiring key", func(t *testing.T) { cmd := models.AddApiKeyCommand{OrgId: 1, Name: "non-expiring", Key: "asd1", SecondsToLive: 0} err := AddApiKey(&cmd) assert.Nil(t, err) query := models.GetApiKeyByNameQuery{KeyName: "non-expiring", OrgId: 1} err = GetApiKeyByName(&query) assert.Nil(t, err) assert.Nil(t, query.Result.Expires) }) t.Run("Add an expiring key", func(t *testing.T) { // expires in one hour cmd := models.AddApiKeyCommand{OrgId: 1, Name: "expiring-in-an-hour", Key: "asd2", SecondsToLive: 3600} err := AddApiKey(&cmd) assert.Nil(t, err) query := models.GetApiKeyByNameQuery{KeyName: "expiring-in-an-hour", OrgId: 1} err = GetApiKeyByName(&query) assert.Nil(t, err) assert.True(t, *query.Result.Expires >= timeNow().Unix()) // timeNow() has been called twice since creation; once by AddApiKey and once by GetApiKeyByName // therefore two seconds should be subtracted by next value returned by timeNow() // that equals the number by which timeSeed has been advanced then := timeNow().Add(-2 * time.Second) expected := then.Add(1 * time.Hour).UTC().Unix() assert.Equal(t, *query.Result.Expires, expected) }) t.Run("Add a key with negative lifespan", func(t *testing.T) { // expires in one day cmd := models.AddApiKeyCommand{OrgId: 1, Name: "key-with-negative-lifespan", Key: "asd3", SecondsToLive: -3600} err := AddApiKey(&cmd) assert.EqualError(t, err, models.ErrInvalidApiKeyExpiration.Error()) query := models.GetApiKeyByNameQuery{KeyName: "key-with-negative-lifespan", OrgId: 1} err = GetApiKeyByName(&query) assert.EqualError(t, err, "invalid API key") }) t.Run("Add keys", func(t *testing.T) { // never expires cmd := models.AddApiKeyCommand{OrgId: 1, Name: "key1", Key: "key1", SecondsToLive: 0} err := AddApiKey(&cmd) assert.Nil(t, err) // expires in 1s cmd = models.AddApiKeyCommand{OrgId: 1, Name: "key2", Key: "key2", SecondsToLive: 1} err = AddApiKey(&cmd) assert.Nil(t, err) // expires in one hour cmd = models.AddApiKeyCommand{OrgId: 1, Name: "key3", Key: "key3", SecondsToLive: 3600} err = AddApiKey(&cmd) assert.Nil(t, err) // advance mocked getTime by 1s timeNow() query := models.GetApiKeysQuery{OrgId: 1, IncludeExpired: false} err = GetApiKeys(&query) assert.Nil(t, err) for _, k := range query.Result { if k.Name == "key2" { t.Fatalf("key2 should not be there") } } query = models.GetApiKeysQuery{OrgId: 1, IncludeExpired: true} err = GetApiKeys(&query) assert.Nil(t, err) found := false for _, k := range query.Result { if k.Name == "key2" { found = true } } assert.True(t, found) }) }) } func TestApiKeyErrors(t *testing.T) { mockTimeNow() defer resetTimeNow() t.Run("Testing API Key errors", func(t *testing.T) { InitTestDB(t) t.Run("Delete non-existing key should return error", func(t *testing.T) { cmd := models.DeleteApiKeyCommand{Id: 1} err := DeleteApiKeyCtx(context.Background(), &cmd) assert.EqualError(t, err, models.ErrApiKeyNotFound.Error()) }) t.Run("Testing API Duplicate Key Errors", func(t *testing.T) { t.Run("Given saved api key", func(t *testing.T) { cmd := models.AddApiKeyCommand{OrgId: 0, Name: "duplicate", Key: "asd"} err := AddApiKey(&cmd) assert.Nil(t, err) t.Run("Add API Key with existing Org ID and Name", func(t *testing.T) { cmd := models.AddApiKeyCommand{OrgId: 0, Name: "duplicate", Key: "asd"} err = AddApiKey(&cmd) assert.EqualError(t, err, models.ErrDuplicateApiKey.Error()) }) }) }) }) }