mirror of
https://github.com/grafana/grafana.git
synced 2024-11-24 09:50:29 -06:00
Storage: Cleanup object history API (#56215)
This commit is contained in:
parent
7715672fb3
commit
4fc9b9aa35
@ -6030,11 +6030,9 @@ exports[`better eslint`] = {
|
|||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "14"],
|
[0, 0, 0, "Do not use any type assertions.", "14"],
|
||||||
[0, 0, 0, "Do not use any type assertions.", "15"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "16"],
|
[0, 0, 0, "Unexpected any. Specify a different type.", "16"]
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "17"],
|
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "18"]
|
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx:5381": [
|
"public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx:5381": [
|
||||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||||
|
@ -17,9 +17,15 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ObjectVersionWithBody struct {
|
||||||
|
*object.ObjectVersionInfo `json:"info,omitempty"`
|
||||||
|
|
||||||
|
Body []byte `json:"body,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type RawObjectWithHistory struct {
|
type RawObjectWithHistory struct {
|
||||||
*object.RawObject `json:"rawObject,omitempty"`
|
*object.RawObject `json:"rawObject,omitempty"`
|
||||||
History []*object.RawObject `json:"history,omitempty"`
|
History []*ObjectVersionWithBody `json:"history,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -74,13 +80,26 @@ func (i dummyObjectServer) findObject(ctx context.Context, uid string, kind stri
|
|||||||
|
|
||||||
getLatestVersion := version == ""
|
getLatestVersion := version == ""
|
||||||
if getLatestVersion {
|
if getLatestVersion {
|
||||||
objVersion := obj.History[len(obj.History)-1]
|
return obj, obj.RawObject, nil
|
||||||
return obj, objVersion, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, objVersion := range obj.History {
|
for _, objVersion := range obj.History {
|
||||||
if objVersion.Version == version {
|
if objVersion.Version == version {
|
||||||
return obj, objVersion, nil
|
copy := &object.RawObject{
|
||||||
|
UID: obj.UID,
|
||||||
|
Kind: obj.Kind,
|
||||||
|
Created: obj.Created,
|
||||||
|
CreatedBy: obj.CreatedBy,
|
||||||
|
Modified: objVersion.Modified,
|
||||||
|
ModifiedBy: objVersion.ModifiedBy,
|
||||||
|
ETag: objVersion.ETag,
|
||||||
|
Version: objVersion.Version,
|
||||||
|
|
||||||
|
// Body is added from the dummy server cache (it does not exist in ObjectVersionInfo)
|
||||||
|
Body: objVersion.Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj, copy, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +144,7 @@ func createContentsHash(contents []byte) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
|
func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
|
||||||
var updated *object.RawObject
|
rsp := &object.WriteObjectResponse{}
|
||||||
|
|
||||||
updatedCount, err := i.collection.Update(ctx, namespace, func(i *RawObjectWithHistory) (bool, *RawObjectWithHistory, error) {
|
updatedCount, err := i.collection.Update(ctx, namespace, func(i *RawObjectWithHistory) (bool, *RawObjectWithHistory, error) {
|
||||||
match := i.UID == r.UID && i.Kind == r.Kind
|
match := i.UID == r.UID && i.Kind == r.Kind
|
||||||
@ -144,7 +163,7 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ
|
|||||||
|
|
||||||
modifier := userFromContext(ctx)
|
modifier := userFromContext(ctx)
|
||||||
|
|
||||||
updated = &object.RawObject{
|
updated := &object.RawObject{
|
||||||
UID: r.UID,
|
UID: r.UID,
|
||||||
Kind: r.Kind,
|
Kind: r.Kind,
|
||||||
Created: i.Created,
|
Created: i.Created,
|
||||||
@ -158,12 +177,32 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ
|
|||||||
ETag: createContentsHash(r.Body),
|
ETag: createContentsHash(r.Body),
|
||||||
Body: r.Body,
|
Body: r.Body,
|
||||||
Version: fmt.Sprintf("%d", prevVersion+1),
|
Version: fmt.Sprintf("%d", prevVersion+1),
|
||||||
Comment: r.Comment,
|
}
|
||||||
|
|
||||||
|
versionInfo := &ObjectVersionWithBody{
|
||||||
|
Body: r.Body,
|
||||||
|
ObjectVersionInfo: &object.ObjectVersionInfo{
|
||||||
|
Version: updated.Version,
|
||||||
|
Modified: updated.Modified,
|
||||||
|
ModifiedBy: updated.ModifiedBy,
|
||||||
|
Size: updated.Size,
|
||||||
|
ETag: updated.ETag,
|
||||||
|
Comment: r.Comment,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rsp.Object = versionInfo.ObjectVersionInfo
|
||||||
|
rsp.Status = object.WriteObjectResponse_MODIFIED
|
||||||
|
|
||||||
|
// When saving, it must be different than the head version
|
||||||
|
if i.ETag == updated.ETag {
|
||||||
|
versionInfo.ObjectVersionInfo.Version = i.Version
|
||||||
|
rsp.Status = object.WriteObjectResponse_UNCHANGED
|
||||||
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, &RawObjectWithHistory{
|
return true, &RawObjectWithHistory{
|
||||||
RawObject: updated,
|
RawObject: updated,
|
||||||
History: append(i.History, updated),
|
History: append(i.History, versionInfo),
|
||||||
}, nil
|
}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -171,14 +210,11 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if updatedCount == 0 {
|
if updatedCount == 0 && rsp.Object == nil {
|
||||||
return nil, fmt.Errorf("could not find object with uid %s and kind %s", r.UID, r.Kind)
|
return nil, fmt.Errorf("could not find object with uid %s and kind %s", r.UID, r.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &object.WriteObjectResponse{
|
return rsp, nil
|
||||||
Error: nil,
|
|
||||||
Object: updated,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
|
func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) {
|
||||||
@ -200,11 +236,23 @@ func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequ
|
|||||||
ETag: createContentsHash(r.Body),
|
ETag: createContentsHash(r.Body),
|
||||||
Body: r.Body,
|
Body: r.Body,
|
||||||
Version: fmt.Sprintf("%d", 1),
|
Version: fmt.Sprintf("%d", 1),
|
||||||
Comment: r.Comment,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info := &object.ObjectVersionInfo{
|
||||||
|
Version: rawObj.Version,
|
||||||
|
Modified: rawObj.Modified,
|
||||||
|
ModifiedBy: rawObj.ModifiedBy,
|
||||||
|
Size: rawObj.Size,
|
||||||
|
ETag: rawObj.ETag,
|
||||||
|
Comment: r.Comment,
|
||||||
|
}
|
||||||
|
|
||||||
newObj := &RawObjectWithHistory{
|
newObj := &RawObjectWithHistory{
|
||||||
RawObject: rawObj,
|
RawObject: rawObj,
|
||||||
History: []*object.RawObject{rawObj},
|
History: []*ObjectVersionWithBody{{
|
||||||
|
ObjectVersionInfo: info,
|
||||||
|
Body: r.Body,
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := i.collection.Insert(ctx, namespace, newObj)
|
err := i.collection.Insert(ctx, namespace, newObj)
|
||||||
@ -214,13 +262,17 @@ func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequ
|
|||||||
|
|
||||||
return &object.WriteObjectResponse{
|
return &object.WriteObjectResponse{
|
||||||
Error: nil,
|
Error: nil,
|
||||||
Object: newObj.RawObject,
|
Object: info,
|
||||||
|
Status: object.WriteObjectResponse_CREATED,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i dummyObjectServer) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) {
|
func (i dummyObjectServer) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) {
|
||||||
namespace := namespaceFromUID(r.UID)
|
namespace := namespaceFromUID(r.UID)
|
||||||
obj, err := i.collection.FindFirst(ctx, namespace, func(i *RawObjectWithHistory) (bool, error) {
|
obj, err := i.collection.FindFirst(ctx, namespace, func(i *RawObjectWithHistory) (bool, error) {
|
||||||
|
if i == nil || r == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
return i.UID == r.UID, nil
|
return i.UID == r.UID, nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -263,15 +315,15 @@ func (i dummyObjectServer) History(ctx context.Context, r *object.ObjectHistoryR
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj == nil {
|
rsp := &object.ObjectHistoryResponse{}
|
||||||
return &object.ObjectHistoryResponse{
|
if obj != nil {
|
||||||
Object: nil,
|
// Return the most recent versions first
|
||||||
}, nil
|
// Better? save them in this order?
|
||||||
|
for i := len(obj.History) - 1; i >= 0; i-- {
|
||||||
|
rsp.Versions = append(rsp.Versions, obj.History[i].ObjectVersionInfo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return rsp, nil
|
||||||
return &object.ObjectHistoryResponse{
|
|
||||||
Object: obj.History,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) {
|
func (i dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) {
|
||||||
|
@ -60,6 +60,14 @@ func parseRequestParams(req *http.Request) (uid string, kind string, params map[
|
|||||||
uid = path
|
uid = path
|
||||||
kind = "?"
|
kind = "?"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read parameters that are encoded in the URL
|
||||||
|
vals := req.URL.Query()
|
||||||
|
for k, v := range vals {
|
||||||
|
if len(v) > 0 {
|
||||||
|
params[k] = v[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +159,7 @@ func (s *httpObjectStore) doWriteObject(c *models.ReqContext) response.Response
|
|||||||
Kind: kind,
|
Kind: kind,
|
||||||
Body: b,
|
Body: b,
|
||||||
Comment: params["comment"],
|
Comment: params["comment"],
|
||||||
PreviousVersion: params["previous"],
|
PreviousVersion: params["previousVersion"],
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(500, "?", err)
|
return response.Error(500, "?", err)
|
||||||
@ -164,7 +172,7 @@ func (s *httpObjectStore) doDeleteObject(c *models.ReqContext) response.Response
|
|||||||
rsp, err := s.store.Delete(c.Req.Context(), &DeleteObjectRequest{
|
rsp, err := s.store.Delete(c.Req.Context(), &DeleteObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
Kind: kind,
|
Kind: kind,
|
||||||
PreviousVersion: params["previous"],
|
PreviousVersion: params["previousVersion"],
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(500, "?", err)
|
return response.Error(500, "?", err)
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() { //nolint:gochecknoinits
|
|
||||||
//jsoniter.RegisterTypeEncoder("object.ReadObjectResponse", &readObjectResponseCodec{})
|
|
||||||
jsoniter.RegisterTypeEncoder("object.RawObject", &rawObjectCodec{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unlike the standard JSON marshal, this will write bytes as JSON when it can
|
|
||||||
type rawObjectCodec struct{}
|
|
||||||
|
|
||||||
// Custom marshal for RawObject (if JSON body)
|
|
||||||
func (obj *RawObject) MarshalJSON() ([]byte, error) {
|
|
||||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
|
||||||
return json.Marshal(obj)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (codec *rawObjectCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
|
||||||
f := (*RawObject)(ptr)
|
|
||||||
return f.UID == "" && f.Body == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (codec *rawObjectCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) {
|
|
||||||
obj := (*RawObject)(ptr)
|
|
||||||
stream.WriteObjectStart()
|
|
||||||
stream.WriteObjectField("UID")
|
|
||||||
stream.WriteString(obj.UID)
|
|
||||||
|
|
||||||
if obj.Kind != "" {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("kind")
|
|
||||||
stream.WriteString(obj.Kind)
|
|
||||||
}
|
|
||||||
if obj.Created > 0 {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("created")
|
|
||||||
stream.WriteInt64(obj.Created)
|
|
||||||
}
|
|
||||||
if obj.CreatedBy != nil {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("createdBy")
|
|
||||||
stream.WriteVal(obj.CreatedBy)
|
|
||||||
}
|
|
||||||
if obj.Modified > 0 {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("modified")
|
|
||||||
stream.WriteInt64(obj.Modified)
|
|
||||||
}
|
|
||||||
if obj.ModifiedBy != nil {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("modifiedBy")
|
|
||||||
stream.WriteVal(obj.ModifiedBy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if obj.Size > 0 {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("size")
|
|
||||||
stream.WriteInt64(obj.Size)
|
|
||||||
}
|
|
||||||
if obj.ETag != "" {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("etag")
|
|
||||||
stream.WriteString(obj.ETag)
|
|
||||||
}
|
|
||||||
if obj.Version != "" {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("version")
|
|
||||||
stream.WriteString(obj.Version)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The one real difference (encodes JSON things directly)
|
|
||||||
if obj.Body != nil {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("body")
|
|
||||||
if json.Valid(obj.Body) {
|
|
||||||
stream.WriteRaw(string(obj.Body)) // works for strings
|
|
||||||
} else {
|
|
||||||
stream.WriteString("// link to raw bytes //")
|
|
||||||
//stream.WriteVal(obj.Body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if obj.SyncSrc != "" {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("syncSrc")
|
|
||||||
stream.WriteString(obj.SyncSrc)
|
|
||||||
}
|
|
||||||
if obj.SyncTime > 0 {
|
|
||||||
stream.WriteMore()
|
|
||||||
stream.WriteObjectField("syncTime")
|
|
||||||
stream.WriteInt64(obj.SyncTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.WriteObjectEnd()
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -47,20 +47,15 @@ message RawObject {
|
|||||||
// NOTE: currently managed by the dashboard+dashboard_version tables
|
// NOTE: currently managed by the dashboard+dashboard_version tables
|
||||||
string version = 10;
|
string version = 10;
|
||||||
|
|
||||||
// optional "save" or "commit" message
|
|
||||||
//
|
|
||||||
// NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command
|
|
||||||
string comment = 11;
|
|
||||||
|
|
||||||
// Location (path/repo/etc) that defines the canonocal form
|
// Location (path/repo/etc) that defines the canonocal form
|
||||||
//
|
//
|
||||||
// NOTE: currently managed by the dashboard_provisioning table
|
// NOTE: currently managed by the dashboard_provisioning table
|
||||||
string sync_src = 12;
|
string sync_src = 11;
|
||||||
|
|
||||||
// Time in epoch milliseconds that the object was last synced with an external system (provisioning/git)
|
// Time in epoch milliseconds that the object was last synced with an external system (provisioning/git)
|
||||||
//
|
//
|
||||||
// NOTE: currently managed by the dashboard_provisioning table
|
// NOTE: currently managed by the dashboard_provisioning table
|
||||||
int64 sync_time = 13;
|
int64 sync_time = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report error while working with objects
|
// Report error while working with objects
|
||||||
@ -76,6 +71,29 @@ message ObjectErrorInfo {
|
|||||||
bytes details_json = 3;
|
bytes details_json = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a subset of RawObject that does not include body or sync info
|
||||||
|
message ObjectVersionInfo {
|
||||||
|
// The version will change when the object is saved. It is not necessarily sortable
|
||||||
|
string version = 1;
|
||||||
|
|
||||||
|
// Time in epoch milliseconds that the object was modified
|
||||||
|
int64 modified = 2;
|
||||||
|
|
||||||
|
// Who modified the object
|
||||||
|
UserInfo modified_by = 3;
|
||||||
|
|
||||||
|
// Content Length
|
||||||
|
int64 size = 4;
|
||||||
|
|
||||||
|
// MD5 digest of the body
|
||||||
|
string ETag = 5;
|
||||||
|
|
||||||
|
// optional "save" or "commit" message
|
||||||
|
//
|
||||||
|
// NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command
|
||||||
|
string comment = 6;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
// Get request/response
|
// Get request/response
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
@ -143,10 +161,21 @@ message WriteObjectResponse {
|
|||||||
ObjectErrorInfo error = 1;
|
ObjectErrorInfo error = 1;
|
||||||
|
|
||||||
// Object details with the body removed
|
// Object details with the body removed
|
||||||
RawObject object = 2;
|
ObjectVersionInfo object = 2;
|
||||||
|
|
||||||
// Object summary as JSON
|
// Object summary as JSON
|
||||||
bytes summary_json = 3;
|
bytes summary_json = 3;
|
||||||
|
|
||||||
|
// Status code
|
||||||
|
Status status = 4;
|
||||||
|
|
||||||
|
// Status enumeration
|
||||||
|
enum Status {
|
||||||
|
ERROR = 0;
|
||||||
|
CREATED = 1;
|
||||||
|
MODIFIED = 2;
|
||||||
|
UNCHANGED = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
@ -188,7 +217,7 @@ message ObjectHistoryRequest {
|
|||||||
|
|
||||||
message ObjectHistoryResponse {
|
message ObjectHistoryResponse {
|
||||||
// Object metadata without the raw bytes
|
// Object metadata without the raw bytes
|
||||||
repeated RawObject object = 1;
|
repeated ObjectVersionInfo versions = 1;
|
||||||
|
|
||||||
// More results exist... pass this in the next request
|
// More results exist... pass this in the next request
|
||||||
string next_page_token = 2;
|
string next_page_token = 2;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.2.0
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
// - protoc v3.21.5
|
// - protoc v3.21.7
|
||||||
// source: object.proto
|
// source: object.proto
|
||||||
|
|
||||||
package object
|
package object
|
||||||
|
@ -29,12 +29,23 @@ type rawObjectMatcher struct {
|
|||||||
modifiedBy *object.UserInfo
|
modifiedBy *object.UserInfo
|
||||||
body []byte
|
body []byte
|
||||||
version *string
|
version *string
|
||||||
|
}
|
||||||
|
|
||||||
|
type objectVersionMatcher struct {
|
||||||
|
modifiedRange []time.Time
|
||||||
|
modifiedBy *object.UserInfo
|
||||||
|
version *string
|
||||||
|
etag *string
|
||||||
comment *string
|
comment *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func userInfoMatches(expected *object.UserInfo, actual *object.UserInfo) (bool, string) {
|
func userInfoMatches(expected *object.UserInfo, actual *object.UserInfo) (bool, string) {
|
||||||
var mismatches []string
|
var mismatches []string
|
||||||
|
|
||||||
|
if actual == nil && expected != nil {
|
||||||
|
return true, "Missing user info"
|
||||||
|
}
|
||||||
|
|
||||||
if expected.Id != actual.Id {
|
if expected.Id != actual.Id {
|
||||||
mismatches = append(mismatches, fmt.Sprintf("expected ID %d, actual ID: %d", expected.Id, actual.Id))
|
mismatches = append(mismatches, fmt.Sprintf("expected ID %d, actual ID: %d", expected.Id, actual.Id))
|
||||||
}
|
}
|
||||||
@ -52,6 +63,8 @@ func timestampInRange(ts int64, tsRange []time.Time) bool {
|
|||||||
|
|
||||||
func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) {
|
func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
require.NotNil(t, obj)
|
||||||
|
|
||||||
mismatches := ""
|
mismatches := ""
|
||||||
if m.uid != nil && *m.uid != obj.UID {
|
if m.uid != nil && *m.uid != obj.UID {
|
||||||
mismatches += fmt.Sprintf("expected UID: %s, actual UID: %s\n", *m.uid, obj.UID)
|
mismatches += fmt.Sprintf("expected UID: %s, actual UID: %s\n", *m.uid, obj.UID)
|
||||||
@ -66,7 +79,7 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(m.modifiedRange) == 2 && !timestampInRange(obj.Modified, m.modifiedRange) {
|
if len(m.modifiedRange) == 2 && !timestampInRange(obj.Modified, m.modifiedRange) {
|
||||||
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 createdBy range: [from %s to %s], actual created: %s\n", m.modifiedRange[0], m.modifiedRange[1], time.Unix(obj.Modified, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.createdBy != nil {
|
if m.createdBy != nil {
|
||||||
@ -97,8 +110,30 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher)
|
|||||||
mismatches += fmt.Sprintf("expected version: %s, actual version: %s\n", *m.version, obj.Version)
|
mismatches += fmt.Sprintf("expected version: %s, actual version: %s\n", *m.version, obj.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.comment != nil && *m.comment != obj.Comment {
|
require.True(t, len(mismatches) == 0, mismatches)
|
||||||
mismatches += fmt.Sprintf("expected comment: %s, actual comment: %s\n", *m.comment, obj.Comment)
|
}
|
||||||
|
|
||||||
|
func requireVersionMatch(t *testing.T, obj *object.ObjectVersionInfo, m objectVersionMatcher) {
|
||||||
|
t.Helper()
|
||||||
|
mismatches := ""
|
||||||
|
|
||||||
|
if m.etag != nil && *m.etag != obj.ETag {
|
||||||
|
mismatches += fmt.Sprintf("expected etag: %s, actual etag: %s\n", *m.etag, obj.ETag)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(m.modifiedRange) == 2 && !timestampInRange(obj.Modified, m.modifiedRange) {
|
||||||
|
mismatches += fmt.Sprintf("expected createdBy range: [from %s to %s], actual created: %s\n", m.modifiedRange[0], m.modifiedRange[1], time.Unix(obj.Modified, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.modifiedBy != nil {
|
||||||
|
userInfoMatches, msg := userInfoMatches(m.modifiedBy, obj.ModifiedBy)
|
||||||
|
if !userInfoMatches {
|
||||||
|
mismatches += fmt.Sprintf("modifiedBy: %s\n", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.version != nil && *m.version != obj.Version {
|
||||||
|
mismatches += fmt.Sprintf("expected version: %s, actual version: %s\n", *m.version, obj.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
require.True(t, len(mismatches) == 0, mismatches)
|
require.True(t, len(mismatches) == 0, mismatches)
|
||||||
@ -144,18 +179,13 @@ func TestObjectServer(t *testing.T) {
|
|||||||
writeResp, err := testCtx.client.Write(ctx, writeReq)
|
writeResp, err := testCtx.client.Write(ctx, writeReq)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
objectMatcher := rawObjectMatcher{
|
versionMatcher := objectVersionMatcher{
|
||||||
uid: &uid,
|
|
||||||
kind: &kind,
|
|
||||||
createdRange: []time.Time{before, time.Now()},
|
|
||||||
modifiedRange: []time.Time{before, time.Now()},
|
modifiedRange: []time.Time{before, time.Now()},
|
||||||
createdBy: fakeUser,
|
|
||||||
modifiedBy: fakeUser,
|
modifiedBy: fakeUser,
|
||||||
body: body,
|
|
||||||
version: &firstVersion,
|
version: &firstVersion,
|
||||||
comment: &writeReq.Comment,
|
comment: &writeReq.Comment,
|
||||||
}
|
}
|
||||||
requireObjectMatch(t, writeResp.Object, objectMatcher)
|
requireVersionMatch(t, writeResp.Object, versionMatcher)
|
||||||
|
|
||||||
readResp, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
|
readResp, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
@ -165,7 +195,18 @@ func TestObjectServer(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Nil(t, readResp.SummaryJson)
|
require.Nil(t, readResp.SummaryJson)
|
||||||
requireObjectMatch(t, writeResp.Object, objectMatcher)
|
|
||||||
|
objectMatcher := rawObjectMatcher{
|
||||||
|
uid: &uid,
|
||||||
|
kind: &kind,
|
||||||
|
createdRange: []time.Time{before, time.Now()},
|
||||||
|
modifiedRange: []time.Time{before, time.Now()},
|
||||||
|
createdBy: fakeUser,
|
||||||
|
modifiedBy: fakeUser,
|
||||||
|
body: body,
|
||||||
|
version: &firstVersion,
|
||||||
|
}
|
||||||
|
requireObjectMatch(t, readResp.Object, objectMatcher)
|
||||||
|
|
||||||
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
|
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
@ -195,6 +236,7 @@ func TestObjectServer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
writeResp1, err := testCtx.client.Write(ctx, writeReq1)
|
writeResp1, err := testCtx.client.Write(ctx, writeReq1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, object.WriteObjectResponse_CREATED, writeResp1.Status)
|
||||||
|
|
||||||
body2 := []byte("{\"name\":\"John2\"}")
|
body2 := []byte("{\"name\":\"John2\"}")
|
||||||
|
|
||||||
@ -208,6 +250,14 @@ func TestObjectServer(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEqual(t, writeResp1.Object.Version, writeResp2.Object.Version)
|
require.NotEqual(t, writeResp1.Object.Version, writeResp2.Object.Version)
|
||||||
|
|
||||||
|
// Duplicate write (no change)
|
||||||
|
writeDupRsp, err := testCtx.client.Write(ctx, writeReq2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, writeDupRsp.Error)
|
||||||
|
require.Equal(t, object.WriteObjectResponse_UNCHANGED, writeDupRsp.Status)
|
||||||
|
require.Equal(t, writeResp2.Object.Version, writeDupRsp.Object.Version)
|
||||||
|
require.Equal(t, writeResp2.Object.ETag, writeDupRsp.Object.ETag)
|
||||||
|
|
||||||
body3 := []byte("{\"name\":\"John3\"}")
|
body3 := []byte("{\"name\":\"John3\"}")
|
||||||
writeReq3 := &object.WriteObjectRequest{
|
writeReq3 := &object.WriteObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
@ -228,7 +278,6 @@ func TestObjectServer(t *testing.T) {
|
|||||||
modifiedBy: fakeUser,
|
modifiedBy: fakeUser,
|
||||||
body: body3,
|
body: body3,
|
||||||
version: &writeResp3.Object.Version,
|
version: &writeResp3.Object.Version,
|
||||||
comment: &writeReq3.Comment,
|
|
||||||
}
|
}
|
||||||
readRespLatest, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
|
readRespLatest, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
@ -259,7 +308,6 @@ func TestObjectServer(t *testing.T) {
|
|||||||
modifiedBy: fakeUser,
|
modifiedBy: fakeUser,
|
||||||
body: body,
|
body: body,
|
||||||
version: &firstVersion,
|
version: &firstVersion,
|
||||||
comment: &writeReq1.Comment,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
history, err := testCtx.client.History(ctx, &object.ObjectHistoryRequest{
|
history, err := testCtx.client.History(ctx, &object.ObjectHistoryRequest{
|
||||||
@ -267,11 +315,11 @@ func TestObjectServer(t *testing.T) {
|
|||||||
Kind: kind,
|
Kind: kind,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, []*object.RawObject{
|
require.Equal(t, []*object.ObjectVersionInfo{
|
||||||
writeResp1.Object,
|
|
||||||
writeResp2.Object,
|
|
||||||
writeResp3.Object,
|
writeResp3.Object,
|
||||||
}, history.Object)
|
writeResp2.Object,
|
||||||
|
writeResp1.Object,
|
||||||
|
}, history.Versions)
|
||||||
|
|
||||||
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
|
deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{
|
||||||
UID: uid,
|
UID: uid,
|
||||||
@ -316,19 +364,47 @@ func TestObjectServer(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
search, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
|
search, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
|
||||||
Kind: []string{kind, kind2},
|
Kind: []string{kind, kind2},
|
||||||
|
WithBody: false,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, []*object.RawObject{
|
|
||||||
w1.Object, w2.Object, w3.Object, w4.Object,
|
|
||||||
}, search.Results)
|
|
||||||
|
|
||||||
|
require.NotNil(t, search)
|
||||||
|
uids := make([]string, 0, len(search.Results))
|
||||||
|
kinds := make([]string, 0, len(search.Results))
|
||||||
|
version := make([]string, 0, len(search.Results))
|
||||||
|
for _, res := range search.Results {
|
||||||
|
uids = append(uids, res.UID)
|
||||||
|
kinds = append(kinds, res.Kind)
|
||||||
|
version = append(version, res.Version)
|
||||||
|
}
|
||||||
|
require.Equal(t, []string{"my-test-entity", "uid2", "uid3", "uid4"}, uids)
|
||||||
|
require.Equal(t, []string{"dashboard", "dashboard", "kind2", "kind2"}, kinds)
|
||||||
|
require.Equal(t, []string{
|
||||||
|
w1.Object.Version,
|
||||||
|
w2.Object.Version,
|
||||||
|
w3.Object.Version,
|
||||||
|
w4.Object.Version,
|
||||||
|
}, version)
|
||||||
|
|
||||||
|
// Again with only one kind
|
||||||
searchKind1, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
|
searchKind1, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{
|
||||||
Kind: []string{kind},
|
Kind: []string{kind},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, []*object.RawObject{
|
uids = make([]string, 0, len(searchKind1.Results))
|
||||||
w1.Object, w2.Object,
|
kinds = make([]string, 0, len(searchKind1.Results))
|
||||||
}, searchKind1.Results)
|
version = make([]string, 0, len(searchKind1.Results))
|
||||||
|
for _, res := range searchKind1.Results {
|
||||||
|
uids = append(uids, res.UID)
|
||||||
|
kinds = append(kinds, res.Kind)
|
||||||
|
version = append(version, res.Version)
|
||||||
|
}
|
||||||
|
require.Equal(t, []string{"my-test-entity", "uid2"}, uids)
|
||||||
|
require.Equal(t, []string{"dashboard", "dashboard"}, kinds)
|
||||||
|
require.Equal(t, []string{
|
||||||
|
w1.Object.Version,
|
||||||
|
w2.Object.Version,
|
||||||
|
}, version)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user