2021-05-11 13:10:19 +08:00
package libraryelements
import (
2021-11-29 17:18:01 +08:00
"bytes"
2021-05-11 13:10:19 +08:00
"context"
"encoding/json"
2021-11-29 17:18:01 +08:00
"io"
2021-05-11 13:10:19 +08:00
"net/http"
"testing"
"time"
"github.com/google/go-cmp/cmp"
2023-04-20 17:24:41 +08:00
"github.com/stretchr/testify/mock"
2022-03-11 01:19:50 +08:00
"github.com/stretchr/testify/require"
2021-05-11 13:10:19 +08:00
"github.com/grafana/grafana/pkg/api/response"
2024-07-26 21:39:23 +08:00
"github.com/grafana/grafana/pkg/apimachinery/identity"
2022-10-18 21:31:56 +08:00
"github.com/grafana/grafana/pkg/bus"
2022-10-19 21:02:15 +08:00
"github.com/grafana/grafana/pkg/infra/db"
2023-09-06 17:16:10 +08:00
"github.com/grafana/grafana/pkg/infra/log"
2022-10-18 21:31:56 +08:00
"github.com/grafana/grafana/pkg/infra/tracing"
2023-01-30 12:14:12 +08:00
"github.com/grafana/grafana/pkg/kinds/librarypanel"
2023-04-20 17:24:41 +08:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
2022-03-10 19:58:18 +08:00
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
2023-01-27 15:50:36 +08:00
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
2021-05-11 13:10:19 +08:00
"github.com/grafana/grafana/pkg/services/dashboards"
2022-03-10 19:58:18 +08:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2022-11-10 17:41:03 +08:00
"github.com/grafana/grafana/pkg/services/folder"
2025-01-28 07:39:18 +08:00
"github.com/grafana/grafana/pkg/services/folder/foldertest"
2023-02-02 00:32:05 +08:00
"github.com/grafana/grafana/pkg/services/libraryelements/model"
2025-01-28 07:39:18 +08:00
ngstore "github.com/grafana/grafana/pkg/services/ngalert/store"
2022-08-10 17:56:48 +08:00
"github.com/grafana/grafana/pkg/services/org"
2022-12-08 00:03:22 +08:00
"github.com/grafana/grafana/pkg/services/org/orgimpl"
2025-01-28 07:39:18 +08:00
"github.com/grafana/grafana/pkg/services/publicdashboards"
2022-11-15 03:08:10 +08:00
"github.com/grafana/grafana/pkg/services/quota/quotatest"
2023-02-07 00:50:03 +08:00
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
2022-06-28 20:32:25 +08:00
"github.com/grafana/grafana/pkg/services/user"
2022-12-08 00:03:22 +08:00
"github.com/grafana/grafana/pkg/services/user/userimpl"
2024-02-09 22:35:39 +08:00
"github.com/grafana/grafana/pkg/tests/testsuite"
2021-10-11 20:30:59 +08:00
"github.com/grafana/grafana/pkg/web"
2021-05-11 13:10:19 +08:00
)
const userInDbName = "user_in_db"
const userInDbAvatar = "/avatar/402d08de060496d6b6874495fe20f5ad"
2024-02-09 22:35:39 +08:00
func TestMain ( m * testing . M ) {
testsuite . Run ( m )
}
2025-04-24 22:10:03 +08:00
func TestIntegration_DeleteLibraryPanelsInFolder ( t * testing . T ) {
2025-07-28 19:38:54 +08:00
if testing . Short ( ) {
t . Skip ( "skipping integration test in short mode" )
}
2021-05-11 13:10:19 +08:00
scenarioWithPanel ( t , "When an admin tries to delete a folder that contains connected library elements, it should fail" ,
func ( t * testing . T , sc scenarioContext ) {
2025-07-30 05:52:57 +08:00
err := sc . service . ConnectElementsToDashboard ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , [ ] string { sc . initialResult . Result . UID } , 1 )
2021-05-11 13:10:19 +08:00
require . NoError ( t , err )
2022-11-11 21:28:24 +08:00
err = sc . service . DeleteLibraryElementsInFolder ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , sc . folder . UID )
2023-02-02 00:32:05 +08:00
require . EqualError ( t , err , model . ErrFolderHasConnectedLibraryElements . Error ( ) )
2021-05-11 13:10:19 +08:00
} )
2021-11-30 21:07:04 +08:00
scenarioWithPanel ( t , "When an admin tries to delete a folder uid that doesn't exist, it should fail" ,
func ( t * testing . T , sc scenarioContext ) {
2025-05-15 22:55:19 +08:00
sc . service . AccessControl = acimpl . ProvideAccessControl ( featuremgmt . WithFeatures ( ) )
sc . service . AccessControl . RegisterScopeAttributeResolver ( dashboards . NewFolderUIDScopeResolver ( sc . service . folderService ) )
2025-06-27 16:09:02 +08:00
sc . ctx . Req = web . SetURLParams ( sc . ctx . Req , map [ string ] string { ":uid" : sc . folder . UID + "xxxx" } )
resp := sc . service . deleteHandler ( sc . reqContext )
require . Equal ( t , http . StatusNotFound , resp . Status ( ) )
2021-11-30 21:07:04 +08:00
} )
2021-05-11 13:10:19 +08:00
scenarioWithPanel ( t , "When an admin tries to delete a folder that contains disconnected elements, it should delete all disconnected elements too" ,
func ( t * testing . T , sc scenarioContext ) {
2023-11-21 04:44:51 +08:00
// nolint:staticcheck
2025-06-12 21:41:18 +08:00
command := getCreatePanelCommand ( sc . folder . ID , sc . folder . UID , "query0" )
2021-11-29 17:18:01 +08:00
sc . reqContext . Req . Body = mockRequestBody ( command )
resp := sc . service . createHandler ( sc . reqContext )
2021-05-11 13:10:19 +08:00
require . Equal ( t , 200 , resp . Status ( ) )
resp = sc . service . getAllHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
var result libraryElementsSearch
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
require . NotNil ( t , result . Result )
require . Equal ( t , 2 , len ( result . Result . Elements ) )
2022-11-11 21:28:24 +08:00
err = sc . service . DeleteLibraryElementsInFolder ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , sc . folder . UID )
2021-05-11 13:10:19 +08:00
require . NoError ( t , err )
resp = sc . service . getAllHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
err = json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
require . NotNil ( t , result . Result )
require . Equal ( t , 0 , len ( result . Result . Elements ) )
} )
}
2025-04-24 22:10:03 +08:00
func TestIntegration_GetLibraryPanelConnections ( t * testing . T ) {
2025-07-28 19:38:54 +08:00
if testing . Short ( ) {
t . Skip ( "skipping integration test in short mode" )
}
2022-07-26 06:55:28 +08:00
scenarioWithPanel ( t , "When an admin tries to get connections of library panel, it should succeed and return correct result" ,
func ( t * testing . T , sc scenarioContext ) {
2025-07-30 05:52:57 +08:00
err := sc . service . ConnectElementsToDashboard ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , [ ] string { sc . initialResult . Result . UID } , 1 )
2022-07-26 06:55:28 +08:00
require . NoError ( t , err )
2025-01-28 02:35:30 +08:00
// add a connection where the dashboard doesn't exist. Shouldn't be returned in the list
err = sc . service . ConnectElementsToDashboard ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , [ ] string { sc . initialResult . Result . UID } , 99999999 )
require . NoError ( t , err )
2023-02-02 00:32:05 +08:00
var expected = func ( res model . LibraryElementConnectionsResponse ) model . LibraryElementConnectionsResponse {
return model . LibraryElementConnectionsResponse {
Result : [ ] model . LibraryElementConnectionDTO {
2022-07-26 06:55:28 +08:00
{
2025-07-30 05:52:57 +08:00
ID : sc . initialResult . Result . ID ,
Kind : sc . initialResult . Result . Kind ,
ElementID : 1 ,
ConnectionID : 1 ,
Created : res . Result [ 0 ] . Created ,
2023-01-30 12:14:12 +08:00
CreatedBy : librarypanel . LibraryElementDTOMetaUser {
Id : 1 ,
2022-07-26 06:55:28 +08:00
Name : userInDbName ,
2023-01-30 12:14:12 +08:00
AvatarUrl : userInDbAvatar ,
2022-07-26 06:55:28 +08:00
} ,
} ,
} ,
}
}
2025-07-30 05:52:57 +08:00
sc . dashboardSvc . On ( "GetDashboardsByLibraryPanelUID" , mock . Anything , mock . Anything , mock . Anything ) . Return ( [ ] * dashboards . DashboardRef {
{
ID : 1 ,
UID : "" ,
} ,
} , nil )
2022-07-26 06:55:28 +08:00
sc . ctx . Req = web . SetURLParams ( sc . ctx . Req , map [ string ] string { ":uid" : sc . initialResult . Result . UID } )
resp := sc . service . getConnectionsHandler ( sc . reqContext )
var result = validateAndUnMarshalConnectionResponse ( t , resp )
if diff := cmp . Diff ( expected ( result ) , result , getCompareOptions ( ) ... ) ; diff != "" {
t . Fatalf ( "Result mismatch (-want +got):\n%s" , diff )
}
} )
2025-01-28 07:39:18 +08:00
scenarioWithPanel ( t , "When an admin tries to create a connection with an element that exists, but the original folder does not, it should still succeed" ,
func ( t * testing . T , sc scenarioContext ) {
b , err := json . Marshal ( map [ string ] string { "test" : "test" } )
require . NoError ( t , err )
2025-06-27 16:09:02 +08:00
newFolder := createFolder ( t , sc , "NewFolder" , sc . folderSvc )
2025-04-10 20:42:23 +08:00
sc . reqContext . Permissions [ sc . reqContext . OrgID ] [ dashboards . ActionFoldersRead ] = [ ] string { dashboards . ScopeFoldersAll }
sc . reqContext . Permissions [ sc . reqContext . OrgID ] [ dashboards . ActionFoldersDelete ] = [ ] string { dashboards . ScopeFoldersAll }
2025-01-28 07:39:18 +08:00
_ , err = sc . service . createLibraryElement ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , model . CreateLibraryElementCommand {
FolderID : newFolder . ID , // nolint:staticcheck
FolderUID : & newFolder . UID ,
Name : "Testing Library Panel With Deleted Folder" ,
Kind : 1 ,
Model : b ,
UID : "panel-with-deleted-folder" ,
} )
require . NoError ( t , err )
err = sc . service . folderService . Delete ( sc . reqContext . Req . Context ( ) , & folder . DeleteFolderCommand {
UID : newFolder . UID ,
OrgID : sc . reqContext . OrgID ,
SignedInUser : sc . reqContext . SignedInUser ,
} )
require . NoError ( t , err )
2025-07-30 05:52:57 +08:00
err = sc . service . ConnectElementsToDashboard ( sc . reqContext . Req . Context ( ) , sc . reqContext . SignedInUser , [ ] string { sc . initialResult . Result . UID } , 1 )
2025-01-28 07:39:18 +08:00
require . NoError ( t , err )
} )
2022-07-26 06:55:28 +08:00
}
2021-05-11 13:10:19 +08:00
type libraryElement struct {
2023-11-07 00:31:15 +08:00
ID int64 ` json:"id" `
OrgID int64 ` json:"orgId" `
// Deprecated: use FolderUID instead
2023-02-02 00:32:05 +08:00
FolderID int64 ` json:"folderId" `
2024-04-09 18:27:43 +08:00
FolderUID string ` json:"folderUid" `
2023-02-02 00:32:05 +08:00
UID string ` json:"uid" `
Name string ` json:"name" `
Kind int64 ` json:"kind" `
Type string ` json:"type" `
Description string ` json:"description" `
2023-08-30 23:46:47 +08:00
Model map [ string ] any ` json:"model" `
2023-02-02 00:32:05 +08:00
Version int64 ` json:"version" `
Meta model . LibraryElementDTOMeta ` json:"meta" `
2021-05-11 13:10:19 +08:00
}
type libraryElementResult struct {
Result libraryElement ` json:"result" `
}
2021-05-14 22:03:37 +08:00
type libraryElementArrayResult struct {
Result [ ] libraryElement ` json:"result" `
}
2021-05-11 13:10:19 +08:00
type libraryElementsSearch struct {
Result libraryElementsSearchResult ` json:"result" `
}
type libraryElementsSearchResult struct {
TotalCount int64 ` json:"totalCount" `
Elements [ ] libraryElement ` json:"elements" `
Page int ` json:"page" `
PerPage int ` json:"perPage" `
}
2024-04-09 18:27:43 +08:00
func getCreatePanelCommand ( folderID int64 , folderUID string , name string ) model . CreateLibraryElementCommand {
command := getCreateCommandWithModel ( folderID , folderUID , name , model . PanelElement , [ ] byte ( `
2021-05-11 13:10:19 +08:00
{
"datasource" : "${DS_GDEV-TESTDATA}" ,
"id" : 1 ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
"description" : "A description"
}
` ) )
return command
}
2024-04-09 18:27:43 +08:00
func getCreateCommandWithModel ( folderID int64 , folderUID , name string , kind model . LibraryElementKind , byteModel [ ] byte ) model . CreateLibraryElementCommand {
2023-02-02 00:32:05 +08:00
command := model . CreateLibraryElementCommand {
2024-04-09 18:27:43 +08:00
FolderUID : & folderUID ,
Name : name ,
Model : byteModel ,
Kind : int64 ( kind ) ,
2021-05-11 13:10:19 +08:00
}
return command
}
type scenarioContext struct {
2021-10-11 20:30:59 +08:00
ctx * web . Context
2021-05-11 13:10:19 +08:00
service * LibraryElementService
2023-01-27 15:50:36 +08:00
reqContext * contextmodel . ReqContext
2022-08-10 17:56:48 +08:00
user user . SignedInUser
2022-11-11 21:28:24 +08:00
folder * folder . Folder
2021-05-11 13:10:19 +08:00
initialResult libraryElementResult
2022-10-15 03:33:06 +08:00
sqlStore db . DB
2023-09-06 17:16:10 +08:00
log log . Logger
2025-07-30 05:52:57 +08:00
folderSvc * foldertest . FakeService
dashboardSvc * dashboards . FakeDashboardService
2021-05-11 13:10:19 +08:00
}
2025-07-30 05:52:57 +08:00
func createFolder ( t * testing . T , sc scenarioContext , title string , folderSvc * foldertest . FakeService ) * folder . Folder {
2021-05-11 13:10:19 +08:00
t . Helper ( )
2024-07-26 21:39:23 +08:00
ctx := identity . WithRequester ( context . Background ( ) , & sc . user )
2025-07-30 05:52:57 +08:00
f , err := folderSvc . Create ( ctx , & folder . CreateFolderCommand {
2025-01-27 17:51:41 +08:00
OrgID : sc . user . OrgID , Title : title , UID : "uid_for_" + title , SignedInUser : & sc . user ,
2022-11-10 17:41:03 +08:00
} )
2021-05-11 13:10:19 +08:00
require . NoError ( t , err )
2025-07-30 05:52:57 +08:00
folderSvc . ExpectedFolder = f
folderSvc . ExpectedFolders = append ( folderSvc . ExpectedFolders , f )
2021-05-11 13:10:19 +08:00
2023-04-20 17:24:41 +08:00
// Set user permissions on the newly created folder so that they can interact with library elements stored in it
2025-07-30 05:52:57 +08:00
sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionFoldersWrite ] = append ( sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionFoldersWrite ] , dashboards . ScopeFoldersProvider . GetResourceScopeUID ( f . UID ) )
sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionFoldersRead ] = append ( sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionFoldersRead ] , dashboards . ScopeFoldersProvider . GetResourceScopeUID ( f . UID ) )
sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionDashboardsCreate ] = append ( sc . reqContext . Permissions [ sc . user . OrgID ] [ dashboards . ActionDashboardsCreate ] , dashboards . ScopeFoldersProvider . GetResourceScopeUID ( f . UID ) )
2021-05-11 13:10:19 +08:00
2025-07-30 05:52:57 +08:00
return f
2021-05-11 13:10:19 +08:00
}
func validateAndUnMarshalResponse ( t * testing . T , resp response . Response ) libraryElementResult {
t . Helper ( )
require . Equal ( t , 200 , resp . Status ( ) )
var result = libraryElementResult { }
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
2021-05-14 22:03:37 +08:00
return result
}
2023-02-02 00:32:05 +08:00
func validateAndUnMarshalConnectionResponse ( t * testing . T , resp response . Response ) model . LibraryElementConnectionsResponse {
2022-07-26 06:55:28 +08:00
t . Helper ( )
require . Equal ( t , 200 , resp . Status ( ) )
2023-02-02 00:32:05 +08:00
var result = model . LibraryElementConnectionsResponse { }
2022-07-26 06:55:28 +08:00
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
return result
}
2021-05-14 22:03:37 +08:00
func validateAndUnMarshalArrayResponse ( t * testing . T , resp response . Response ) libraryElementArrayResult {
t . Helper ( )
require . Equal ( t , 200 , resp . Status ( ) )
var result = libraryElementArrayResult { }
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
2021-05-11 13:10:19 +08:00
return result
}
2025-06-27 16:09:02 +08:00
// setupTestScenario performs the common setup for library element tests
func setupTestScenario ( t * testing . T ) scenarioContext {
2021-05-11 13:10:19 +08:00
t . Helper ( )
2023-04-20 17:24:41 +08:00
2025-06-27 16:09:02 +08:00
orgID := int64 ( 1 )
role := org . RoleAdmin
usr := user . SignedInUser {
UserID : 1 ,
Name : "Signed In User" ,
Login : "signed_in_user" ,
Email : "signed.in.user@test.com" ,
OrgID : orgID ,
OrgRole : role ,
LastSeenAt : time . Now ( ) ,
// Allow user to create folders and library elements
Permissions : map [ int64 ] map [ string ] [ ] string {
1 : {
dashboards . ActionFoldersCreate : { dashboards . ScopeFoldersAll } ,
dashboards . ActionFoldersWrite : { dashboards . ScopeFoldersAll } ,
dashboards . ActionFoldersRead : { dashboards . ScopeFoldersAll } ,
ActionLibraryPanelsCreate : { dashboards . ScopeFoldersAll } ,
ActionLibraryPanelsRead : { ScopeLibraryPanelsAll } ,
ActionLibraryPanelsWrite : { ScopeLibraryPanelsAll } ,
ActionLibraryPanelsDelete : { ScopeLibraryPanelsAll } ,
} ,
} ,
}
req := & http . Request {
Header : http . Header {
"Content-Type" : [ ] string { "application/json" } ,
} ,
}
ctx := identity . WithRequester ( context . Background ( ) , & usr )
req = req . WithContext ( ctx )
webCtx := web . Context { Req : req }
2023-11-13 23:55:15 +08:00
features := featuremgmt . WithFeatures ( )
2025-06-27 16:09:02 +08:00
tracer := tracing . InitializeTracerForTest ( )
2024-09-26 07:21:39 +08:00
sqlStore , cfg := db . InitTestDBWithCfg ( t )
2025-06-30 19:18:19 +08:00
t . Cleanup ( db . CleanupTestDB )
2023-04-20 17:24:41 +08:00
quotaService := quotatest . New ( false , nil )
2025-06-27 16:09:02 +08:00
ac := acimpl . ProvideAccessControl ( features )
2023-04-20 17:24:41 +08:00
folderPermissions := acmock . NewMockedPermissionsService ( )
2025-06-27 16:09:02 +08:00
folderPermissions . On ( "SetPermissions" , mock . Anything , mock . Anything , mock . Anything , mock . Anything ) . Return ( [ ] accesscontrol . ResourcePermission { } , nil )
publicDash := & publicdashboards . FakePublicDashboardServiceWrapper { }
publicDash . On ( "DeleteByDashboardUIDs" , mock . Anything , mock . Anything , mock . Anything ) . Return ( nil )
2025-07-30 05:52:57 +08:00
folderSvc := foldertest . NewFakeService ( )
f := & folder . Folder {
ID : 1 ,
OrgID : 1 ,
UID : "uid_for_ScenarioFolder" ,
Title : "ScenarioFolder" ,
}
folderSvc . ExpectedFolder = f
folderSvc . ExpectedFolders = [ ] * folder . Folder { f }
dashService := dashboards . NewFakeDashboardService ( t )
2025-06-27 16:09:02 +08:00
alertStore , err := ngstore . ProvideDBStore ( cfg , features , sqlStore , & foldertest . FakeService { } , & dashboards . FakeDashboardService { } , ac , bus . ProvideBus ( tracing . InitializeTracerForTest ( ) ) )
require . NoError ( t , err )
err = folderSvc . RegisterService ( alertStore )
require . NoError ( t , err )
service := LibraryElementService {
Cfg : cfg ,
features : featuremgmt . WithFeatures ( ) ,
SQLStore : sqlStore ,
folderService : folderSvc ,
dashboardsService : dashService ,
AccessControl : ac ,
log : log . NewNopLogger ( ) ,
}
service . AccessControl . RegisterScopeAttributeResolver ( LibraryPanelUIDScopeResolver ( & service , folderSvc ) )
// deliberate difference between signed in user and user in db to make it crystal clear
// what to expect in the tests
// In the real world these are identical
cmd := user . CreateUserCommand {
Email : "user.in.db@test.com" ,
Name : "User In DB" ,
Login : userInDbName ,
}
orgSvc , err := orgimpl . ProvideService ( sqlStore , cfg , quotaService )
require . NoError ( t , err )
usrSvc , err := userimpl . ProvideService (
sqlStore , orgSvc , cfg , nil , nil , tracer ,
quotaService , supportbundlestest . NewFakeBundleService ( ) ,
)
require . NoError ( t , err )
_ , err = usrSvc . Create ( context . Background ( ) , & cmd )
require . NoError ( t , err )
sc := scenarioContext {
user : usr ,
ctx : & webCtx ,
service : & service ,
sqlStore : sqlStore ,
reqContext : & contextmodel . ReqContext {
Context : & webCtx ,
SignedInUser : & usr ,
} ,
2025-07-30 05:52:57 +08:00
folderSvc : folderSvc ,
dashboardSvc : dashService ,
2025-06-27 16:09:02 +08:00
}
sc . folder = createFolder ( t , sc , "ScenarioFolder" , folderSvc )
return sc
}
func scenarioWithPanel ( t * testing . T , desc string , fn func ( t * testing . T , sc scenarioContext ) ) {
t . Helper ( )
t . Run ( desc , func ( t * testing . T ) {
sc := setupTestScenario ( t )
2021-05-11 13:10:19 +08:00
2023-11-21 04:44:51 +08:00
// nolint:staticcheck
2024-04-09 18:27:43 +08:00
command := getCreatePanelCommand ( sc . folder . ID , sc . folder . UID , "Text - Library Panel" )
2021-11-29 17:18:01 +08:00
sc . reqContext . Req . Body = mockRequestBody ( command )
resp := sc . service . createHandler ( sc . reqContext )
2021-05-11 13:10:19 +08:00
sc . initialResult = validateAndUnMarshalResponse ( t , resp )
2023-09-06 17:16:10 +08:00
sc . log = log . New ( "libraryelements-test" )
2021-05-11 13:10:19 +08:00
fn ( t , sc )
} )
}
// testScenario is a wrapper around t.Run performing common setup for library panel tests.
// It takes your real test function as a callback.
func testScenario ( t * testing . T , desc string , fn func ( t * testing . T , sc scenarioContext ) ) {
t . Helper ( )
t . Run ( desc , func ( t * testing . T ) {
2025-06-27 16:09:02 +08:00
sc := setupTestScenario ( t )
2021-05-11 13:10:19 +08:00
fn ( t , sc )
} )
}
func getCompareOptions ( ) [ ] cmp . Option {
return [ ] cmp . Option {
cmp . Transformer ( "Time" , func ( in time . Time ) int64 {
return in . UTC ( ) . Unix ( )
} ) ,
}
}
2021-11-29 17:18:01 +08:00
2023-08-30 23:46:47 +08:00
func mockRequestBody ( v any ) io . ReadCloser {
2021-11-29 17:18:01 +08:00
b , _ := json . Marshal ( v )
return io . NopCloser ( bytes . NewReader ( b ) )
}