2025-01-14 05:15:35 +08:00
package folderimpl
import (
"context"
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"testing"
2025-01-24 04:23:59 +08:00
"github.com/stretchr/testify/mock"
2025-01-14 05:15:35 +08:00
"github.com/stretchr/testify/require"
2025-01-22 12:45:59 +08:00
"google.golang.org/grpc"
2025-01-22 04:42:38 +08:00
clientrest "k8s.io/client-go/rest"
2025-01-14 05:15:35 +08:00
"github.com/grafana/grafana/pkg/apimachinery/identity"
2025-01-22 12:45:59 +08:00
"github.com/grafana/grafana/pkg/apimachinery/utils"
2025-01-14 05:15:35 +08:00
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/log/logtest"
"github.com/grafana/grafana/pkg/infra/tracing"
internalfolders "github.com/grafana/grafana/pkg/registry/apis/folders"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
2025-01-22 04:42:38 +08:00
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
2025-01-14 05:15:35 +08:00
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/guardian"
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
2025-01-24 04:23:59 +08:00
"github.com/grafana/grafana/pkg/services/publicdashboards"
2025-01-14 05:15:35 +08:00
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
2025-01-22 12:45:59 +08:00
"github.com/grafana/grafana/pkg/storage/unified/resource"
2025-01-14 05:15:35 +08:00
)
2025-01-22 04:42:38 +08:00
type rcp struct {
Host string
}
func ( r rcp ) GetRestConfig ( ctx context . Context ) * clientrest . Config {
return & clientrest . Config {
Host : r . Host ,
}
}
2025-01-14 05:15:35 +08:00
func TestIntegrationFolderServiceViaUnifiedStorage ( t * testing . T ) {
if testing . Short ( ) {
t . Skip ( "skipping integration test" )
}
m := map [ string ] v0alpha1 . Folder { }
unifiedStorageFolder := & v0alpha1 . Folder { }
unifiedStorageFolder . Kind = "folder"
fooFolder := & folder . Folder {
2025-01-22 12:45:59 +08:00
ID : 123 ,
2025-01-14 05:15:35 +08:00
Title : "Foo Folder" ,
OrgID : orgID ,
UID : "foo" ,
URL : "/dashboards/f/foo/foo-folder" ,
CreatedByUID : "user:1" ,
UpdatedByUID : "user:1" ,
}
updateFolder := & folder . Folder {
Title : "Folder" ,
OrgID : orgID ,
UID : "updatefolder" ,
}
mux := http . NewServeMux ( )
mux . HandleFunc ( "DELETE /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/deletefolder" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
} )
mux . HandleFunc ( "GET /apis/folder.grafana.app/v0alpha1/namespaces/default/folders" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
l := & v0alpha1 . FolderList { }
l . Kind = "Folder"
err := json . NewEncoder ( w ) . Encode ( l )
require . NoError ( t , err )
} )
mux . HandleFunc ( "GET /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/foo" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
namespacer := func ( _ int64 ) string { return "1" }
result , err := internalfolders . LegacyFolderToUnstructured ( fooFolder , namespacer )
require . NoError ( t , err )
err = json . NewEncoder ( w ) . Encode ( result )
require . NoError ( t , err )
} )
mux . HandleFunc ( "GET /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/updatefolder" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
namespacer := func ( _ int64 ) string { return "1" }
result , err := internalfolders . LegacyFolderToUnstructured ( updateFolder , namespacer )
require . NoError ( t , err )
err = json . NewEncoder ( w ) . Encode ( result )
require . NoError ( t , err )
} )
mux . HandleFunc ( "PUT /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/updatefolder" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
buf , err := io . ReadAll ( req . Body )
require . NoError ( t , err )
var foldr v0alpha1 . Folder
err = json . Unmarshal ( buf , & foldr )
require . NoError ( t , err )
updateFolder . Title = foldr . Spec . Title
namespacer := func ( _ int64 ) string { return "1" }
result , err := internalfolders . LegacyFolderToUnstructured ( updateFolder , namespacer )
require . NoError ( t , err )
err = json . NewEncoder ( w ) . Encode ( result )
require . NoError ( t , err )
} )
mux . HandleFunc ( "GET /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/ady4yobv315a8e" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
err := json . NewEncoder ( w ) . Encode ( unifiedStorageFolder )
require . NoError ( t , err )
} )
mux . HandleFunc ( "PUT /apis/folder.grafana.app/v0alpha1/namespaces/default/folders/ady4yobv315a8e" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
err := json . NewEncoder ( w ) . Encode ( unifiedStorageFolder )
require . NoError ( t , err )
} )
mux . HandleFunc ( "POST /apis/folder.grafana.app/v0alpha1/namespaces/default/folders" , func ( w http . ResponseWriter , req * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json" )
buf , err := io . ReadAll ( req . Body )
require . NoError ( t , err )
var folder v0alpha1 . Folder
err = json . Unmarshal ( buf , & folder )
require . NoError ( t , err )
m [ folder . Name ] = folder
fmt . Printf ( "buf: %+v\n" , folder )
folder . Kind = "Folder"
err = json . NewEncoder ( w ) . Encode ( folder )
require . NoError ( t , err )
} )
folderApiServerMock := httptest . NewServer ( mux )
defer folderApiServerMock . Close ( )
origNewGuardian := guardian . New
t . Cleanup ( func ( ) {
guardian . New = origNewGuardian
} )
db , cfg := sqlstore . InitTestDB ( t )
cfg . AppURL = folderApiServerMock . URL
2025-01-22 04:42:38 +08:00
restCfgProvider := rcp {
Host : folderApiServerMock . URL ,
}
2025-01-22 12:45:59 +08:00
f := func ( ctx context . Context ) resource . ResourceClient {
return resourceClientMock { }
}
2025-01-22 04:42:38 +08:00
k8sHandler := & foldk8sHandler {
2025-01-22 12:45:59 +08:00
gvr : v0alpha1 . FolderResourceInfo . GroupVersionResource ( ) ,
namespacer : request . GetNamespaceMapper ( cfg ) ,
cfg : cfg ,
restConfigProvider : restCfgProvider . GetRestConfig ,
recourceClientProvider : f ,
2025-01-22 04:42:38 +08:00
}
unifiedStore := ProvideUnifiedStore ( k8sHandler )
2025-01-14 05:15:35 +08:00
ctx := context . Background ( )
usr := & user . SignedInUser { UserID : 1 , OrgID : 1 , Permissions : map [ int64 ] map [ string ] [ ] string {
1 : accesscontrol . GroupScopesByActionContext (
ctx ,
[ ] accesscontrol . Permission {
{ Action : dashboards . ActionFoldersCreate , Scope : dashboards . ScopeFoldersAll } ,
{ Action : dashboards . ActionFoldersWrite , Scope : dashboards . ScopeFoldersAll } ,
{ Action : accesscontrol . ActionAlertingRuleDelete , Scope : dashboards . ScopeFoldersAll } ,
} ) ,
} }
alertingStore := ngstore . DBstore {
SQLStore : db ,
Cfg : cfg . UnifiedAlerting ,
Logger : log . New ( "test-alerting-store" ) ,
AccessControl : actest . FakeAccessControl { ExpectedEvaluate : true } ,
}
featuresArr := [ ] any {
featuremgmt . FlagKubernetesFoldersServiceV2 }
features := featuremgmt . WithFeatures ( featuresArr ... )
2025-01-24 04:23:59 +08:00
dashboardStore := dashboards . NewFakeDashboardStore ( t )
publicDashboardService := publicdashboards . NewFakePublicDashboardServiceWrapper ( t )
2025-01-14 05:15:35 +08:00
folderService := & Service {
2025-01-24 04:23:59 +08:00
log : slog . New ( logtest . NewTestHandler ( t ) ) . With ( "logger" , "test-folder-service" ) ,
unifiedStore : unifiedStore ,
features : features ,
bus : bus . ProvideBus ( tracing . InitializeTracerForTest ( ) ) ,
accessControl : acimpl . ProvideAccessControl ( features ) ,
registry : make ( map [ string ] folder . RegistryService ) ,
metrics : newFoldersMetrics ( nil ) ,
tracer : tracing . InitializeTracerForTest ( ) ,
k8sclient : k8sHandler ,
dashboardStore : dashboardStore ,
publicDashboardService : publicDashboardService ,
2025-01-14 05:15:35 +08:00
}
require . NoError ( t , folderService . RegisterService ( alertingStore ) )
t . Run ( "Folder service tests" , func ( t * testing . T ) {
t . Run ( "Given user has no permissions" , func ( t * testing . T ) {
origNewGuardian := guardian . New
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { } )
ctx = identity . WithRequester ( context . Background ( ) , noPermUsr )
f := folder . NewFolder ( "Folder" , "" )
f . UID = "foo"
t . Run ( "When get folder by id should return access denied error" , func ( t * testing . T ) {
_ , err := folderService . Get ( ctx , & folder . GetFolderQuery {
UID : & f . UID ,
OrgID : orgID ,
SignedInUser : noPermUsr ,
} )
require . Equal ( t , dashboards . ErrFolderAccessDenied , err )
} )
t . Run ( "When get folder by uid should return access denied error" , func ( t * testing . T ) {
_ , err := folderService . Get ( ctx , & folder . GetFolderQuery {
UID : & f . UID ,
OrgID : orgID ,
SignedInUser : noPermUsr ,
} )
require . Equal ( t , dashboards . ErrFolderAccessDenied , err )
} )
t . Run ( "When creating folder should return access denied error" , func ( t * testing . T ) {
_ , err := folderService . Create ( ctx , & folder . CreateFolderCommand {
OrgID : orgID ,
Title : f . Title ,
UID : f . UID ,
SignedInUser : noPermUsr ,
} )
require . Error ( t , err )
} )
title := "Folder-TEST"
t . Run ( "When updating folder should return access denied error" , func ( t * testing . T ) {
_ , err := folderService . Update ( ctx , & folder . UpdateFolderCommand {
UID : f . UID ,
OrgID : orgID ,
NewTitle : & title ,
SignedInUser : noPermUsr ,
} )
require . Error ( t , err )
require . Equal ( t , dashboards . ErrFolderAccessDenied , err )
} )
t . Run ( "When deleting folder by uid should return access denied error" , func ( t * testing . T ) {
err := folderService . Delete ( ctx , & folder . DeleteFolderCommand {
UID : f . UID ,
OrgID : orgID ,
ForceDeleteRules : false ,
SignedInUser : noPermUsr ,
} )
require . Error ( t , err )
require . Equal ( t , dashboards . ErrFolderAccessDenied , err )
} )
t . Cleanup ( func ( ) {
guardian . New = origNewGuardian
} )
} )
t . Run ( "Given user has permission to save" , func ( t * testing . T ) {
origNewGuardian := guardian . New
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanSaveValue : true , CanViewValue : true } )
ctx = identity . WithRequester ( context . Background ( ) , usr )
f := & folder . Folder {
OrgID : orgID ,
Title : "Test-Folder" ,
UID : "testfolder" ,
URL : "/dashboards/f/testfolder/test-folder" ,
CreatedByUID : "user:1" ,
UpdatedByUID : "user:1" ,
}
t . Run ( "When creating folder should not return access denied error" , func ( t * testing . T ) {
actualFolder , err := folderService . Create ( ctx , & folder . CreateFolderCommand {
OrgID : orgID ,
Title : f . Title ,
UID : f . UID ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
require . Equal ( t , f , actualFolder )
} )
t . Run ( "When creating folder should return error if uid is general" , func ( t * testing . T ) {
_ , err := folderService . Create ( ctx , & folder . CreateFolderCommand {
OrgID : orgID ,
Title : f . Title ,
UID : "general" ,
SignedInUser : usr ,
} )
require . ErrorIs ( t , err , dashboards . ErrFolderInvalidUID )
} )
t . Run ( "When updating folder should not return access denied error" , func ( t * testing . T ) {
title := "TEST-Folder"
req := & folder . UpdateFolderCommand {
UID : updateFolder . UID ,
OrgID : orgID ,
NewTitle : & title ,
SignedInUser : usr ,
}
reqResult , err := folderService . Update ( ctx , req )
require . NoError ( t , err )
require . Equal ( t , title , reqResult . Title )
} )
t . Run ( "When deleting folder by uid should not return access denied error - ForceDeleteRules true" , func ( t * testing . T ) {
err := folderService . Delete ( ctx , & folder . DeleteFolderCommand {
UID : "deletefolder" ,
OrgID : orgID ,
ForceDeleteRules : true ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
} )
t . Run ( "When deleting folder by uid should not return access denied error - ForceDeleteRules false" , func ( t * testing . T ) {
2025-01-24 04:23:59 +08:00
dashboardStore . On ( "FindDashboards" , mock . Anything , mock . Anything ) . Return ( [ ] dashboards . DashboardSearchProjection { } , nil )
publicDashboardService . On ( "DeleteByDashboardUIDs" , mock . Anything , mock . Anything , mock . Anything ) . Return ( nil )
2025-01-14 05:15:35 +08:00
err := folderService . Delete ( ctx , & folder . DeleteFolderCommand {
UID : "deletefolder" ,
OrgID : orgID ,
ForceDeleteRules : false ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
} )
t . Run ( "When deleting folder by uid, expectedForceDeleteRules as false, and dashboard Restore turned on should not return access denied error" , func ( t * testing . T ) {
folderService . features = featuremgmt . WithFeatures ( append ( featuresArr , featuremgmt . FlagDashboardRestore ) ... )
expectedForceDeleteRules := false
err := folderService . Delete ( ctx , & folder . DeleteFolderCommand {
UID : "deletefolder" ,
OrgID : orgID ,
ForceDeleteRules : expectedForceDeleteRules ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
} )
t . Run ( "When deleting folder by uid, expectedForceDeleteRules as true, and dashboard Restore turned on should not return access denied error" , func ( t * testing . T ) {
folderService . features = featuremgmt . WithFeatures ( append ( featuresArr , featuremgmt . FlagDashboardRestore ) ... )
expectedForceDeleteRules := true
err := folderService . Delete ( ctx , & folder . DeleteFolderCommand {
UID : "deletefolder" ,
OrgID : orgID ,
ForceDeleteRules : expectedForceDeleteRules ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
} )
t . Cleanup ( func ( ) {
guardian . New = origNewGuardian
} )
} )
t . Run ( "Given user has permission to view" , func ( t * testing . T ) {
origNewGuardian := guardian . New
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanViewValue : true } )
t . Run ( "When get folder by uid should return folder" , func ( t * testing . T ) {
actual , err := folderService . Get ( ctx , & folder . GetFolderQuery {
UID : & fooFolder . UID ,
OrgID : fooFolder . OrgID ,
SignedInUser : usr ,
} )
require . Equal ( t , fooFolder , actual )
require . NoError ( t , err )
} )
t . Run ( "When get folder by uid and uid is general should return the root folder object" , func ( t * testing . T ) {
uid := accesscontrol . GeneralFolderUID
query := & folder . GetFolderQuery {
UID : & uid ,
OrgID : 1 ,
SignedInUser : usr ,
}
actual , err := folderService . Get ( ctx , query )
require . Equal ( t , folder . RootFolder , actual )
require . NoError ( t , err )
} )
2025-01-22 12:45:59 +08:00
t . Run ( "When get folder by ID should return folder" , func ( t * testing . T ) {
id := int64 ( 123 )
query := & folder . GetFolderQuery {
ID : & id ,
OrgID : 1 ,
SignedInUser : usr ,
}
actual , err := folderService . Get ( context . Background ( ) , query )
require . Equal ( t , fooFolder , actual )
require . NoError ( t , err )
} )
t . Run ( "When get folder by non existing ID should return not found error" , func ( t * testing . T ) {
id := int64 ( 111111 )
query := & folder . GetFolderQuery {
ID : & id ,
OrgID : 1 ,
SignedInUser : usr ,
}
actual , err := folderService . Get ( context . Background ( ) , query )
require . Nil ( t , actual )
require . ErrorIs ( t , err , dashboards . ErrFolderNotFound )
} )
2025-01-23 03:47:46 +08:00
t . Run ( "When get folder by Title should return folder" , func ( t * testing . T ) {
title := "foo"
query := & folder . GetFolderQuery {
Title : & title ,
OrgID : 1 ,
SignedInUser : usr ,
}
actual , err := folderService . Get ( context . Background ( ) , query )
require . Equal ( t , fooFolder , actual )
require . NoError ( t , err )
} )
t . Run ( "When get folder by non existing Title should return not found error" , func ( t * testing . T ) {
title := "does not exists"
query := & folder . GetFolderQuery {
Title : & title ,
OrgID : 1 ,
SignedInUser : usr ,
}
actual , err := folderService . Get ( context . Background ( ) , query )
require . Nil ( t , actual )
require . ErrorIs ( t , err , dashboards . ErrFolderNotFound )
} )
2025-01-14 05:15:35 +08:00
t . Cleanup ( func ( ) {
guardian . New = origNewGuardian
} )
} )
t . Run ( "Returns root folder" , func ( t * testing . T ) {
t . Run ( "When the folder UID is blank should return the root folder" , func ( t * testing . T ) {
emptyString := ""
actual , err := folderService . Get ( ctx , & folder . GetFolderQuery {
UID : & emptyString ,
OrgID : 1 ,
SignedInUser : usr ,
} )
require . NoError ( t , err )
require . Equal ( t , folder . GeneralFolder . UID , actual . UID )
require . Equal ( t , folder . GeneralFolder . Title , actual . Title )
} )
} )
} )
}
2025-01-22 12:45:59 +08:00
type resourceClientMock struct { }
func ( r resourceClientMock ) Read ( ctx context . Context , in * resource . ReadRequest , opts ... grpc . CallOption ) ( * resource . ReadResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) Create ( ctx context . Context , in * resource . CreateRequest , opts ... grpc . CallOption ) ( * resource . CreateResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) Update ( ctx context . Context , in * resource . UpdateRequest , opts ... grpc . CallOption ) ( * resource . UpdateResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) Delete ( ctx context . Context , in * resource . DeleteRequest , opts ... grpc . CallOption ) ( * resource . DeleteResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) Restore ( ctx context . Context , in * resource . RestoreRequest , opts ... grpc . CallOption ) ( * resource . RestoreResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) List ( ctx context . Context , in * resource . ListRequest , opts ... grpc . CallOption ) ( * resource . ListResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) Watch ( ctx context . Context , in * resource . WatchRequest , opts ... grpc . CallOption ) ( resource . ResourceStore_WatchClient , error ) {
return nil , nil
}
func ( r resourceClientMock ) Search ( ctx context . Context , in * resource . ResourceSearchRequest , opts ... grpc . CallOption ) ( * resource . ResourceSearchResponse , error ) {
if len ( in . Options . Labels ) > 0 &&
in . Options . Labels [ 0 ] . Key == utils . LabelKeyDeprecatedInternalID &&
in . Options . Labels [ 0 ] . Operator == "in" &&
len ( in . Options . Labels [ 0 ] . Values ) > 0 &&
in . Options . Labels [ 0 ] . Values [ 0 ] == "123" {
return & resource . ResourceSearchResponse {
Results : & resource . ResourceTable {
Columns : [ ] * resource . ResourceTableColumnDefinition {
{
Name : "_id" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
{
Name : "title" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
{
Name : "folder" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
} ,
Rows : [ ] * resource . ResourceTableRow {
{
Key : & resource . ResourceKey {
Name : "foo" ,
Resource : "folders" ,
} ,
Cells : [ ] [ ] byte {
[ ] byte ( "123" ) ,
[ ] byte ( "folder1" ) ,
[ ] byte ( "" ) ,
} ,
} ,
} ,
} ,
TotalHits : 1 ,
} , nil
}
2025-01-23 03:47:46 +08:00
if len ( in . Options . Fields ) > 0 &&
in . Options . Fields [ 0 ] . Key == resource . SEARCH_FIELD_TITLE &&
in . Options . Fields [ 0 ] . Operator == "in" &&
len ( in . Options . Fields [ 0 ] . Values ) > 0 &&
in . Options . Fields [ 0 ] . Values [ 0 ] == "foo" {
return & resource . ResourceSearchResponse {
Results : & resource . ResourceTable {
Columns : [ ] * resource . ResourceTableColumnDefinition {
{
Name : "_id" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
{
Name : "title" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
{
Name : "folder" ,
Type : resource . ResourceTableColumnDefinition_STRING ,
} ,
} ,
Rows : [ ] * resource . ResourceTableRow {
{
Key : & resource . ResourceKey {
Name : "foo" ,
Resource : "folders" ,
} ,
Cells : [ ] [ ] byte {
[ ] byte ( "123" ) ,
[ ] byte ( "folder1" ) ,
[ ] byte ( "" ) ,
} ,
} ,
} ,
} ,
TotalHits : 1 ,
} , nil
}
2025-01-22 12:45:59 +08:00
// not found
return & resource . ResourceSearchResponse {
Results : & resource . ResourceTable { } ,
} , nil
}
func ( r resourceClientMock ) GetStats ( ctx context . Context , in * resource . ResourceStatsRequest , opts ... grpc . CallOption ) ( * resource . ResourceStatsResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) CountRepositoryObjects ( ctx context . Context , in * resource . CountRepositoryObjectsRequest , opts ... grpc . CallOption ) ( * resource . CountRepositoryObjectsResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) ListRepositoryObjects ( ctx context . Context , in * resource . ListRepositoryObjectsRequest , opts ... grpc . CallOption ) ( * resource . ListRepositoryObjectsResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) PutBlob ( ctx context . Context , in * resource . PutBlobRequest , opts ... grpc . CallOption ) ( * resource . PutBlobResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) GetBlob ( ctx context . Context , in * resource . GetBlobRequest , opts ... grpc . CallOption ) ( * resource . GetBlobResponse , error ) {
return nil , nil
}
func ( r resourceClientMock ) IsHealthy ( ctx context . Context , in * resource . HealthCheckRequest , opts ... grpc . CallOption ) ( * resource . HealthCheckResponse , error ) {
return nil , nil
}