Provisioning: move repository integration tests to its own package (#120183)

* chore: move provisioning repository integ test own package

* chore: fix mixing variable in test
This commit is contained in:
Gonzalo Trigueros Manzanas
2026-03-12 15:33:56 +01:00
committed by GitHub
parent 941eeda602
commit aae6b52020
3 changed files with 77 additions and 37 deletions
@@ -0,0 +1,11 @@
package repository
import (
"testing"
"github.com/grafana/grafana/pkg/tests/testsuite"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
@@ -1,4 +1,4 @@
package provisioning
package repository
import (
"context"
@@ -1,4 +1,4 @@
package provisioning
package repository
import (
"context"
@@ -38,6 +38,35 @@ import (
"github.com/grafana/grafana/pkg/util/testutil"
)
//nolint:gosec // Test RSA private key (generated for testing purposes only)
const testPrivateKeyPEM = `-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQBn1MuM5hIfH6d3TNStI1ofWv/gcjQ4joi9cFijEwVLuPYkF1nD
KkSbaMGFUWiOTaB/H9fxmd/V2u04NlBY3av6m5T/sHfVSiEWAEUblh3cA34HVCmD
cqyyVty5HLGJJlSs2C7W2x7yUc9ImzyDBsyjpKOXuojJ9wN9a17D2cYU5WkXjoDC
4BHid61jn9WBTtPZXSgOdirwahNzxZQSIP7DA9T8yiZwIWPp5YesgsAPyQLCFPgM
s77xz/CEUnEYQ35zI/k/mQrwKdQ/ZP8xLwQohUID0BIxE7G5quL069RuuCZWZkoF
oPiZbp7HSryz1+19jD3rFT7eHGUYvAyCnXmXAgMBAAECggEADSs4Bc7ITZo+Kytb
bfol3AQ2n8jcRrANN7mgBE7NRSVYUouDnvUlbnCC2t3QXPwLdxQa11GkygLSQ2bg
GeVDgq1o4GUJTcvxFlFCcpU/hEANI/DQsxNAQ/4wUGoLOlHaO3HPvwBblHA70gGe
Ux/xpG+lMAFAiB0EHEwZ4M0mClBEOQv3NzaFTWuBHtIMS8eid7M1q5qz9+rCgZSL
KBBHo0OvUbajG4CWl8SM6LUYapASGg+U17E+4xA3npwpIdsk+CbtX+vvX324n4kn
0EkrJqCjv8M1KiCKAP+UxwP00ywxOg4PN+x+dHI/I7xBvEKe/x6BltVSdGA+PlUK
02wagQKBgQDF7gdQLFIagPH7X7dBP6qEGxj/Ck9Qdz3S1gotPkVeq+1/UtQijYZ1
j44up/0yB2B9P4kW091n+iWcyfoU5UwBua9dHvCZP3QH05LR1ZscUHxLGjDPBASt
l2xSq0hqqNWBspb1M0eCY0Yxi65iDkj3xsI2iN35BEb1FlWdR5KGvwKBgQCGS0ce
wASWbZIPU2UoKGOQkIJU6QmLy0KZbfYkpyfE8IxGttYVEQ8puNvDDNZWHNf+LP85
c8iV6SfnWiLmu1XkG2YmJFBCCAWgJ8Mq2XQD8E+a/xcaW3NqlcC5+I2czX367j3r
69wZSxRbzR+DCfOiIkrekJImwN183ZYy2cBbKQKBgFj86IrSMmO6H5Ft+j06u5ZD
fJyF7Rz3T3NwSgkHWzbyQ4ggHEIgsRg/36P4YSzSBj6phyAdRwkNfUWdxXMJmH+a
FU7frzqnPaqbJAJ1cBRt10QI1XLtkpDdaJVObvONTtjOC3LYiEkGCzQRYeiyFXpZ
AU51gJ8JnkFotjtNR4KPAoGAehVREDlLcl0lnN0ZZspgyPk2Im6/iOA9KTH3xBZZ
ZwWu4FIyiHA7spgk4Ep5R0ttZ9oMI3SIcw/EgONGOy8uw/HMiPwWIhEc3B2JpRiO
CU6bb7JalFFyuQBudiHoyxVcY5PVovWF31CLr3DoJr4TR9+Y5H/U/XnzYCIo+w1N
exECgYBFAGKYTIeGAvhIvD5TphLpbCyeVLBIq5hRyrdRY+6Iwqdr5PGvLPKwin5+
+4CDhWPW4spq8MYPCRiMrvRSctKt/7FhVGL2vE/0VY3TcLk14qLC+2+0lnPVgnYn
u5/wOyuHp1cIBnjeN41/pluOWFBHI9xLW3ExLtmYMiecJ8VdRA==
-----END RSA PRIVATE KEY-----`
func TestIntegrationProvisioning_CreatingAndGetting(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
@@ -46,8 +75,8 @@ func TestIntegrationProvisioning_CreatingAndGetting(t *testing.T) {
ctx := context.Background()
inputFiles := []string{
"testdata/github-readonly.json.tmpl",
"testdata/local-readonly.json.tmpl",
"../testdata/github-readonly.json.tmpl",
"../testdata/local-readonly.json.tmpl",
}
for _, inputFilePath := range inputFiles {
@@ -300,7 +329,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
{
name: "should succeed with valid local repository",
repo: func() *unstructured.Unstructured {
return helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
return helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "valid-repo",
"SyncEnabled": true,
})
@@ -309,7 +338,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
{
name: "should error if mutually exclusive finalizers are set",
repo: func() *unstructured.Unstructured {
localTmp := helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
localTmp := helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "repo-with-invalid-finalizers",
"SyncEnabled": true,
})
@@ -328,7 +357,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
{
name: "should error if unknown finalizer is set",
repo: func() *unstructured.Unstructured {
localTmp := helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
localTmp := helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "repo-with-unknown-finalizer",
"SyncEnabled": true,
})
@@ -487,7 +516,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
for i, test := range pathTests {
t.Run(test.name, func(t *testing.T) {
repoName := fmt.Sprintf("git-path-test-%d", i+1)
gitRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
gitRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": repoName,
"URL": baseURL,
"Path": test.path,
@@ -519,7 +548,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
baseURL := "https://github.com/grafana/test-repo-path-sync-disabled"
// Create an initial repo with sync disabled and a specific path
firstRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
firstRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-sync-disabled-1",
"URL": baseURL,
"Path": "demo/nested",
@@ -531,7 +560,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
// Create a second repo pointing to same URL with a child path and sync disabled.
// This simulates the wizard onboarding flow where sync is not yet enabled.
secondRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
secondRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-sync-disabled-2",
"URL": baseURL,
"Path": "demo/nested/child",
@@ -542,7 +571,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
require.NoError(t, err, "Second repository with child path should succeed when sync is disabled")
// Create a third repo with the same path (duplicate) and sync disabled
thirdRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
thirdRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-sync-disabled-3",
"URL": baseURL,
"Path": "demo/nested",
@@ -553,7 +582,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
require.NoError(t, err, "Third repository with duplicate path should succeed when sync is disabled")
// Create a fourth repo with empty path (root) and sync disabled - wizard step 1 scenario
fourthRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
fourthRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-sync-disabled-4",
"URL": baseURL,
"Path": "",
@@ -569,7 +598,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
baseURL := "https://github.com/grafana/test-repo-enable-sync-conflict"
// Create an initial repo with sync enabled and a specific path
firstRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
firstRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-enable-sync-1",
"URL": baseURL,
"Path": "demo/nested",
@@ -580,7 +609,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
require.NoError(t, err, "First repository should be created successfully")
// Create second repo with conflicting child path but sync disabled (should succeed)
secondRepo := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
secondRepo := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": "git-enable-sync-2",
"URL": baseURL,
"Path": "demo/nested/child",
@@ -598,7 +627,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
})
t.Run("should update sync interval", func(t *testing.T) {
r := helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
r := helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "valid-repo-testinterval",
"SyncEnabled": true,
"SyncIntervalSeconds": 5,
@@ -611,7 +640,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
})
t.Run("should automatically add finalizers during creation", func(t *testing.T) {
r := helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
r := helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "repo-auto-finalizers",
"SyncEnabled": false,
})
@@ -631,7 +660,7 @@ func TestIntegrationProvisioning_RepositoryValidation(t *testing.T) {
t.Run("should re-add finalizers when removed during update", func(t *testing.T) {
// Create a repository with finalizers
r := helper.RenderObject(t, "testdata/local-readonly.json.tmpl", map[string]any{
r := helper.RenderObject(t, "../testdata/local-readonly.json.tmpl", map[string]any{
"Name": "repo-update-finalizers",
"SyncEnabled": false,
})
@@ -672,9 +701,9 @@ func TestIntegrationProvisioning_FailInvalidSchema(t *testing.T) {
const repo = "invalid-schema-tmp"
// Set up the repository and the file to import.
helper.CopyToProvisioningPath(t, "testdata/invalid-dashboard-schema.json", "invalid-dashboard-schema.json")
helper.CopyToProvisioningPath(t, "../testdata/invalid-dashboard-schema.json", "invalid-dashboard-schema.json")
localTmp := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{
localTmp := helper.RenderObject(t, "../testdata/local-write.json.tmpl", map[string]any{
"Name": repo,
"SyncEnabled": true,
})
@@ -729,9 +758,9 @@ func TestIntegrationProvisioning_CreatingGitHubRepository(t *testing.T) {
// treeEntryDir("grafana", "subtree"),
// },
// "subtree": {
// treeEntry("dashboard.json", helper.LoadFile("testdata/all-panels.json")),
// treeEntry("dashboard.json", helper.LoadFile("../testdata/all-panels.json")),
// treeEntryDir("subdir", "subtree2"),
// treeEntry("subdir/dashboard2.yaml", helper.LoadFile("testdata/text-options.json")),
// treeEntry("subdir/dashboard2.yaml", helper.LoadFile("../testdata/text-options.json")),
// },
// })),
@@ -744,7 +773,7 @@ func TestIntegrationProvisioning_CreatingGitHubRepository(t *testing.T) {
const repo = "github-create-test"
testRepo := common.TestRepo{
Name: repo,
Template: "testdata/github-readonly.json.tmpl",
Template: "../testdata/github-readonly.json.tmpl",
Target: "folder",
ExpectedDashboards: 3,
ExpectedFolders: 3, // Folder sync creates an additional folder for the repository itself
@@ -807,7 +836,7 @@ func TestIntegrationProvisioning_CreatingGitHubRepository(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Create repository directly without health checks since we're only testing URL cleanup
input := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
input := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": test.name,
"URL": test.input,
"SyncTarget": "folder",
@@ -837,7 +866,7 @@ func TestIntegrationProvisioning_ReadOnlyRepositoryNoWebhook(t *testing.T) {
t.Run("repository with no workflows should not create a webhook", func(t *testing.T) {
repoName := "readonly-no-webhook"
input := helper.RenderObject(t, "testdata/github-readonly.json.tmpl", map[string]any{
input := helper.RenderObject(t, "../testdata/github-readonly.json.tmpl", map[string]any{
"Name": repoName,
"SyncEnabled": false,
})
@@ -1128,7 +1157,7 @@ func TestIntegrationProvisioning_RepositoryLimits(t *testing.T) {
helper.CreateRepo(t, originalRepo)
t.Run("folder sync is rejected when instance sync exists", func(t *testing.T) {
folderRepo := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{
folderRepo := helper.RenderObject(t, "../testdata/local-write.json.tmpl", map[string]any{
"Name": "folder-blocked-by-instance",
"SyncEnabled": true,
"SyncTarget": "folder",
@@ -1174,7 +1203,7 @@ func TestIntegrationProvisioning_RepositoryLimits(t *testing.T) {
})
t.Run("instance sync rejected when any other repository exists", func(t *testing.T) {
instanceRepo := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{
instanceRepo := helper.RenderObject(t, "../testdata/local-write.json.tmpl", map[string]any{
"Name": "instance-repo-blocked",
"SyncEnabled": true,
"SyncTarget": "instance",
@@ -1223,7 +1252,7 @@ func TestIntegrationProvisioning_RepositoryLimits(t *testing.T) {
// Try to create the 11th repository - should fail due to limit
eleventhRepoName := "limit-test-repo-11"
eleventhRepo := helper.RenderObject(t, "testdata/local-write.json.tmpl", map[string]any{
eleventhRepo := helper.RenderObject(t, "../testdata/local-write.json.tmpl", map[string]any{
"Name": eleventhRepoName,
"SyncEnabled": true,
"SyncTarget": "folder",
@@ -1266,7 +1295,7 @@ func TestIntegrationProvisioning_RunLocalRepository(t *testing.T) {
Resource("repositories").
Name(repo).
SubResource("files", targetPath).
Body(helper.LoadFile("testdata/all-panels.json")).
Body(helper.LoadFile("../testdata/all-panels.json")).
SetHeader("Content-Type", "application/json").
Do(ctx).StatusCode(&code)
require.Equal(t, http.StatusNotFound, code)
@@ -1278,7 +1307,7 @@ func TestIntegrationProvisioning_RunLocalRepository(t *testing.T) {
Resource("repositories").
Name(repo).
SubResource("files", targetPath).
Body(helper.LoadFile("testdata/all-panels.json")).
Body(helper.LoadFile("../testdata/all-panels.json")).
SetHeader("Content-Type", "application/json").
Do(ctx).StatusCode(&code)
require.NoError(t, result.Error(), "expecting to be able to create file")
@@ -1353,7 +1382,7 @@ func TestIntegrationProvisioning_RunLocalRepository(t *testing.T) {
Resource("repositories").
Name(repo).
SubResource("files", "test", "..", "..", "all-panels.json"). // UNSAFE PATH
Body(helper.LoadFile("testdata/all-panels.json")).
Body(helper.LoadFile("../testdata/all-panels.json")).
SetHeader("Content-Type", "application/json").
Do(ctx)
require.Error(t, result.Error(), "invalid path should return error")
@@ -1441,7 +1470,7 @@ func TestIntegrationProvisioning_ImportAllPanelsFromLocalRepository(t *testing.T
testRepo := common.TestRepo{
Name: repo,
Target: "folder",
Copies: map[string]string{"testdata/all-panels.json": "all-panels.json"},
Copies: map[string]string{"../testdata/all-panels.json": "all-panels.json"},
ExpectedDashboards: 1,
ExpectedFolders: 1, // folder sync creates a folder
}
@@ -1500,7 +1529,7 @@ func TestIntegrationProvisioning_DeleteRepositoryAndReleaseResources(t *testing.
const repo = "gh-repo"
testRepo := common.TestRepo{
Name: repo,
Template: "testdata/github-readonly.json.tmpl",
Template: "../testdata/github-readonly.json.tmpl",
Target: "folder",
ExpectedDashboards: 3,
ExpectedFolders: 3,
@@ -1757,7 +1786,7 @@ func TestIntegrationProvisioning_RefsPermissions(t *testing.T) {
const repo = "refs-permissions-test"
testRepo := common.TestRepo{
Name: repo,
Template: "testdata/github-readonly.json.tmpl",
Template: "../testdata/github-readonly.json.tmpl",
Target: "folder",
ExpectedDashboards: 3,
ExpectedFolders: 3, // Repository creates folders
@@ -1821,7 +1850,7 @@ func TestIntegrationProvisioning_EmptyPath(t *testing.T) {
const repo = "empty-path-test"
testRepo := common.TestRepo{
Name: repo,
Template: "testdata/github-empty-path.json.tmpl",
Template: "../testdata/github-empty-path.json.tmpl",
Target: "folder",
Values: map[string]any{
"SyncEnabled": true,
@@ -1849,7 +1878,7 @@ func TestIntegrationProvisioning_EmptyPath(t *testing.T) {
// Step 1: Create first repository with empty path - syncs successfully
testRepo1 := common.TestRepo{
Name: repo1,
Template: "testdata/github-empty-path.json.tmpl",
Template: "../testdata/github-empty-path.json.tmpl",
Target: "folder",
Values: map[string]any{
"SyncEnabled": true,
@@ -1864,7 +1893,7 @@ func TestIntegrationProvisioning_EmptyPath(t *testing.T) {
// but sync should warn because dashboards are owned by repo1
testRepo2 := common.TestRepo{
Name: repo2,
Template: "testdata/github-empty-path.json.tmpl",
Template: "../testdata/github-empty-path.json.tmpl",
Target: "folder",
Values: map[string]any{
"SyncEnabled": true,
@@ -2833,7 +2862,7 @@ func TestIntegrationProvisioning_FolderTitleUpdatesOnSync(t *testing.T) {
helper.CreateRepo(t, common.TestRepo{
Name: repoName,
Target: "folder",
Copies: map[string]string{"testdata/all-panels.json": "all-panels.json"},
Copies: map[string]string{"../testdata/all-panels.json": "all-panels.json"},
ExpectedDashboards: 1,
ExpectedFolders: 1,
Values: map[string]any{