@ -1,8 +1,7 @@
package object_server_tests
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"testing"
@ -10,15 +9,11 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/store/object"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
)
func createContentsHash ( contents [ ] byte ) string {
hash := md5 . Sum ( contents )
return hex . EncodeToString ( hash [ : ] )
}
type rawObjectMatcher struct {
grn * object . GRN
createdRange [ ] time . Time
@ -38,7 +33,9 @@ type objectVersionMatcher struct {
}
func timestampInRange ( ts int64 , tsRange [ ] time . Time ) bool {
return ts >= tsRange [ 0 ] . Unix ( ) && ts <= tsRange [ 1 ] . Unix ( )
low := tsRange [ 0 ] . UnixMilli ( ) - 1
high := tsRange [ 1 ] . UnixMilli ( ) + 1
return ts >= low && ts <= high
}
func requireObjectMatch ( t * testing . T , obj * object . RawObject , m rawObjectMatcher ) {
@ -46,16 +43,27 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher)
require . NotNil ( t , obj )
mismatches := ""
if m . grn != nil && ! obj . GRN . Equals ( m . grn ) {
mismatches += fmt . Sprintf ( "expected: %v, actual: %v\n" , m . grn , obj . GRN )
if m . grn != nil {
if m . grn . TenantId > 0 && m . grn . TenantId != obj . GRN . TenantId {
mismatches += fmt . Sprintf ( "expected tenant: %d, actual: %d\n" , m . grn . TenantId , obj . GRN . TenantId )
}
if m . grn . Scope != "" && m . grn . Scope != obj . GRN . Scope {
mismatches += fmt . Sprintf ( "expected Scope: %s, actual: %s\n" , m . grn . Scope , obj . GRN . Scope )
}
if m . grn . Kind != "" && m . grn . Kind != obj . GRN . Kind {
mismatches += fmt . Sprintf ( "expected Kind: %s, actual: %s\n" , m . grn . Kind , obj . GRN . Kind )
}
if m . grn . UID != "" && m . grn . UID != obj . GRN . UID {
mismatches += fmt . Sprintf ( "expected UID: %s, actual: %s\n" , m . grn . UID , obj . GRN . UID )
}
}
if len ( m . createdRange ) == 2 && ! timestampInRange ( obj . Created , m . createdRange ) {
mismatches += fmt . Sprintf ( "expected createdBy range: [from %s to %s], actual created: %s\n" , m . createdRange [ 0 ] , m . createdRange [ 1 ] , time . Unix ( obj . Created , 0 ) )
mismatches += fmt . Sprintf ( "expected Created range: [from %s to %s], actual created: %s\n" , m . createdRange [ 0 ] , m . createdRange [ 1 ] , time . UnixMilli ( obj . Created ) )
}
if len ( m . updatedRange ) == 2 && ! timestampInRange ( obj . Updated , m . updatedRange ) {
mismatches += fmt . Sprintf ( "expected updatedRange range: [from %s to %s], actual updated: %s\n" , m . updatedRange [ 0 ] , m . updatedRange [ 1 ] , time . Unix ( obj . Updated , 0 ) )
mismatches += fmt . Sprintf ( "expected Updated range: [from %s to %s], actual updated: %s\n" , m . updatedRange [ 0 ] , m . updatedRange [ 1 ] , time . UnixMilli ( obj . Updated ) )
}
if m . createdBy != "" && m . createdBy != obj . CreatedBy {
@ -66,14 +74,12 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher)
mismatches += fmt . Sprintf ( "updatedBy: expected:%s, found:%s\n" , m . updatedBy , obj . UpdatedBy )
}
if ! reflect . DeepEqual ( m . body , obj . Body ) {
mismatches += fmt . Sprintf ( "expected body len: %d, actual body len: %d\n" , len ( m . body ) , len ( obj . Body ) )
}
expectedHash := createContentsHash ( m . body )
actualHash := createContentsHash ( obj . Body )
if expectedHash != actualHash {
mismatches += fmt . Sprintf ( "expected body hash: %s, actual body hash: %s\n" , expectedHash , actualHash )
if len ( m . body ) > 0 {
if json . Valid ( m . body ) {
require . JSONEq ( t , string ( m . body ) , string ( obj . Body ) , "expecting same body" )
} else if ! reflect . DeepEqual ( m . body , obj . Body ) {
mismatches += fmt . Sprintf ( "expected body len: %d, actual body len: %d\n" , len ( m . body ) , len ( obj . Body ) )
}
}
if m . version != nil && * m . version != obj . Version {
@ -92,7 +98,7 @@ func requireVersionMatch(t *testing.T, obj *object.ObjectVersionInfo, m objectVe
}
if len ( m . updatedRange ) == 2 && ! timestampInRange ( obj . Updated , m . updatedRange ) {
mismatches += fmt . Sprintf ( "expected updatedRange range: [from %s to %s], actual updated: %s\n" , m . updatedRange [ 0 ] , m . updatedRange [ 1 ] , time . Unix ( obj . Updated , 0 ) )
mismatches += fmt . Sprintf ( "expected updatedRange range: [from %s to %s], actual updated: %s\n" , m . updatedRange [ 0 ] , m . updatedRange [ 1 ] , time . UnixMilli ( obj . Updated ) )
}
if m . updatedBy != "" && m . updatedBy != obj . UpdatedBy {
@ -120,7 +126,7 @@ func TestObjectServer(t *testing.T) {
grn := & object . GRN {
Kind : kind ,
UID : "my-test-entity" ,
Scope : "entity" ,
Scope : models . ObjectStoreScopeEntity ,
}
body := [ ] byte ( "{\"name\":\"John\"}" )
@ -159,10 +165,11 @@ func TestObjectServer(t *testing.T) {
} )
require . NoError ( t , err )
require . Nil ( t , readResp . SummaryJson )
require . NotNil ( t , readResp . Object )
foundGRN := readResp . Object . GRN
require . NotNil ( t , foundGRN )
require . Not Equal( t , testCtx . user . OrgID , foundGRN . TenantId ) // orgId becomes the tenant id when not set
require . Equal ( t , testCtx . user . OrgID , foundGRN . TenantId ) // orgId becomes the tenant id when not set
require . Equal ( t , grn . Scope , foundGRN . Scope )
require . Equal ( t , grn . Kind , foundGRN . Kind )
require . Equal ( t , grn . UID , foundGRN . UID )
@ -196,6 +203,12 @@ func TestObjectServer(t *testing.T) {
t . Run ( "should be able to update an object" , func ( t * testing . T ) {
before := time . Now ( )
grn := & object . GRN {
Kind : kind ,
UID : util . GenerateShortUID ( ) ,
Scope : models . ObjectStoreScopeEntity ,
}
writeReq1 := & object . WriteObjectRequest {
GRN : grn ,
Body : body ,
@ -302,8 +315,9 @@ func TestObjectServer(t *testing.T) {
w2 , err := testCtx . client . Write ( ctx , & object . WriteObjectRequest {
GRN : & object . GRN {
UID : uid2 ,
Kind : kind ,
UID : uid2 ,
Kind : kind ,
Scope : grn . Scope ,
} ,
Body : body ,
} )
@ -311,8 +325,9 @@ func TestObjectServer(t *testing.T) {
w3 , err := testCtx . client . Write ( ctx , & object . WriteObjectRequest {
GRN : & object . GRN {
UID : uid3 ,
Kind : kind2 ,
UID : uid3 ,
Kind : kind2 ,
Scope : grn . Scope ,
} ,
Body : body ,
} )
@ -320,8 +335,9 @@ func TestObjectServer(t *testing.T) {
w4 , err := testCtx . client . Write ( ctx , & object . WriteObjectRequest {
GRN : & object . GRN {
UID : uid4 ,
Kind : kind2 ,
UID : uid4 ,
Kind : kind2 ,
Scope : grn . Scope ,
} ,
Body : body ,
} )