| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | package sources | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 	"github.com/google/go-cmp/cmp" | 
					
						
							|  |  |  | 	"github.com/google/go-cmp/cmp/cmpopts" | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins/config" | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | var compareOpts = []cmp.Option{cmpopts.IgnoreFields(LocalSource{}, "log"), cmp.AllowUnexported(LocalSource{})} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | func TestDirAsLocalSources(t *testing.T) { | 
					
						
							|  |  |  | 	testdataDir := "../testdata" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tests := []struct { | 
					
						
							|  |  |  | 		name        string | 
					
						
							|  |  |  | 		pluginsPath string | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 		cfg         *config.PluginManagementCfg | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 		expected    []*LocalSource | 
					
						
							|  |  |  | 		err         error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:        "Empty path returns an error", | 
					
						
							|  |  |  | 			pluginsPath: "", | 
					
						
							|  |  |  | 			expected:    []*LocalSource{}, | 
					
						
							|  |  |  | 			err:         errors.New("plugins path not configured"), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:        "Directory with subdirectories", | 
					
						
							|  |  |  | 			pluginsPath: filepath.Join(testdataDir, "pluginRootWithDist"), | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 			cfg:         &config.PluginManagementCfg{}, | 
					
						
							|  |  |  | 			expected: []*LocalSource{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "datasource")}, | 
					
						
							|  |  |  | 					strictMode: true, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "dist")}, | 
					
						
							|  |  |  | 					strictMode: true, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "panel")}, | 
					
						
							|  |  |  | 					strictMode: true, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Dev mode disables strict mode for source", | 
					
						
							|  |  |  | 			cfg: &config.PluginManagementCfg{ | 
					
						
							|  |  |  | 				DevMode: true, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			pluginsPath: filepath.Join(testdataDir, "pluginRootWithDist"), | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 			expected: []*LocalSource{ | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "datasource")}, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 					strictMode: false, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "dist")}, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 					strictMode: false, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 					paths:      []string{filepath.Join(testdataDir, "pluginRootWithDist", "panel")}, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 					strictMode: false, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:        "Directory with no subdirectories", | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 			cfg:         &config.PluginManagementCfg{}, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 			pluginsPath: filepath.Join(testdataDir, "pluginRootWithDist", "datasource"), | 
					
						
							| 
									
										
										
										
											2024-06-15 02:16:36 +08:00
										 |  |  | 			expected:    []*LocalSource{}, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:        "Directory with a symlink to a directory", | 
					
						
							|  |  |  | 			pluginsPath: filepath.Join(testdataDir, "symbolic-plugin-dirs"), | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 			cfg:         &config.PluginManagementCfg{}, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 			expected: []*LocalSource{ | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 					paths:      []string{filepath.Join(testdataDir, "symbolic-plugin-dirs", "plugin")}, | 
					
						
							|  |  |  | 					class:      plugins.ClassExternal, | 
					
						
							|  |  |  | 					strictMode: true, | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for _, tt := range tests { | 
					
						
							|  |  |  | 		t.Run(tt.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 			got, err := DirAsLocalSources(tt.cfg, tt.pluginsPath, plugins.ClassExternal) | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 			if tt.err != nil { | 
					
						
							|  |  |  | 				require.Errorf(t, err, tt.err.Error()) | 
					
						
							| 
									
										
										
										
											2025-06-19 17:28:23 +08:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			if !cmp.Equal(got, tt.expected, compareOpts...) { | 
					
						
							|  |  |  | 				t.Fatalf("Result mismatch (-want +got):\n%s", cmp.Diff(got, tt.expected, compareOpts...)) | 
					
						
							| 
									
										
										
										
											2024-01-18 18:06:33 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |