| package kernelmods |
| |
| import ( |
| "context" |
| "fmt" |
| "os" |
| "path/filepath" |
| "reflect" |
| "strings" |
| "testing" |
| |
| "github.com/fsouza/fake-gcs-server/fakestorage" |
| |
| "cos-extensions/tools/gcs" |
| ) |
| |
| func TestListInstalledModulesDirNonExistent(t *testing.T) { |
| dirName := "nonexistent/" |
| _, err := ListInstalledModules(dirName, false) |
| wantErrMessage := "failed to retrieve module files from directory nonexistent/: failed to validate local directory" |
| if err == nil || !strings.HasPrefix(err.Error(), wantErrMessage) { |
| t.Errorf(" TestListNewModulesDirNonExistent: expected error: %s \t got error: %v", wantErrMessage, err) |
| } |
| } |
| |
| func TestListInstalledModulesSuccessful(t *testing.T) { |
| retrieveInstalledModules = func(moduleFiles []string) (map[string]string, error) { |
| modMap := make(map[string]string) |
| for _, modFile := range moduleFiles { |
| mod := strings.Split(modFile, "/") |
| modName, _ := strings.CutSuffix(mod[len(mod)-1], ".ko") |
| modMap[modFile] = modName |
| } |
| return modMap, nil |
| } |
| tmpDir, err := os.MkdirTemp("", "test-module") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir: %v", err) |
| } |
| defer os.RemoveAll(tmpDir) |
| |
| filePath := filepath.Join(tmpDir, "unknown.txt") |
| _, err = os.Create(filePath) |
| if err != nil { |
| t.Fatalf("Failed to create temp file: %v", err) |
| } |
| filePath = filepath.Join(tmpDir, "module.ko") |
| _, err = os.Create(filePath) |
| if err != nil { |
| t.Fatalf("Failed to create temp file: %v", err) |
| } |
| got, err := ListInstalledModules(tmpDir, false) |
| if err != nil { |
| t.Errorf("TestListModulesSuccessful: error: %v", err) |
| } |
| want := map[string]string{filePath: "module"} |
| if !reflect.DeepEqual(got, want) { |
| t.Errorf("TestListModulesSuccessful: expected module paths: %v\t got module paths: %v", want, got) |
| } |
| } |
| |
| func TestListDownloadedModulesSuccessful(t *testing.T) { |
| tmpDir, err := os.MkdirTemp("", "test-module") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir: %v", err) |
| } |
| defer os.RemoveAll(tmpDir) |
| |
| filePath := filepath.Join(tmpDir, "unknown.txt") |
| _, err = os.Create(filePath) |
| if err != nil { |
| t.Fatalf("Failed to create temp file: %v", err) |
| } |
| filePath = filepath.Join(tmpDir, "module.ko") |
| _, err = os.Create(filePath) |
| if err != nil { |
| t.Fatalf("Failed to create temp file: %v", err) |
| } |
| retrieveLocalModulesInfo = func(moduleFiles []string) map[string]string { |
| modMap := make(map[string]string) |
| for _, modFile := range moduleFiles { |
| mod := strings.Split(modFile, "/") |
| modName, _ := strings.CutSuffix(mod[len(mod)-1], ".ko") |
| modMap[modFile] = modName |
| } |
| return modMap |
| } |
| got, err := ListDownloadedModules(tmpDir, false) |
| if err != nil { |
| t.Errorf("TestListModulesSuccessful: error: %v", err) |
| } |
| want := map[string]string{ |
| filePath: "module", |
| } |
| if !reflect.DeepEqual(got, want) { |
| t.Errorf("TestListDownloadedModulesSuccessful: expected module paths: %v\t got module paths: %v", want, got) |
| } |
| } |
| |
| func TestInstallModules(t *testing.T) { |
| retrieveInstalledModules = func(_ []string) (map[string]string, error) { |
| return map[string]string{"/var/lib/module/skip1.ko": "skip1", "/var/lib/module/skip2.ko": "skip2"}, nil |
| } |
| installModule = func(modPath string, _ []string) error { |
| if modPath == "/var/lib/module/error.ko" { |
| return fmt.Errorf("An error occured") |
| } |
| return nil |
| } |
| tests := []struct { |
| desc string |
| modulePaths []string |
| want []string |
| }{ |
| { |
| desc: "Successfully installs modules", |
| modulePaths: []string{"/var/lib/module/module1.ko", "/var/lib/module/module2.ko"}, |
| want: []string{"/var/lib/module/module1.ko", "/var/lib/module/module2.ko"}, |
| }, { |
| desc: "Skips module already installed.", |
| modulePaths: []string{"/var/lib/module/skip1.ko", "/var/lib/module/module2.ko"}, |
| want: []string{"/var/lib/module/module2.ko"}, |
| }, { |
| desc: "Skips module that fails to install", |
| modulePaths: []string{"/var/lib/module/error.ko", "/var/lib/module/module2.ko"}, |
| want: []string{"/var/lib/module/module2.ko"}, |
| }, |
| } |
| for _, test := range tests { |
| t.Run(test.desc, func(t *testing.T) { |
| got, err := InstallModules(test.modulePaths, []string{}) |
| |
| if err != nil { |
| t.Errorf("TestInstallModules(%s): error: %v", test.desc, err) |
| } |
| |
| if !reflect.DeepEqual(got, test.want) { |
| t.Errorf("TestInstallModules(%s): expected module paths: %s\t got module paths: %s", test.desc, test.want, got) |
| } |
| }) |
| |
| } |
| } |
| |
| func TestDownloadModulesSuccessful(t *testing.T) { |
| ctx := context.Background() |
| tmpDir, err := os.MkdirTemp("", "test-gcs") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir: %v", err) |
| } |
| defer os.RemoveAll(tmpDir) |
| server := fakestorage.NewServer( |
| []fakestorage.Object{ |
| {ObjectAttrs: fakestorage.ObjectAttrs{ |
| BucketName: "my-bucket", Name: "path/to/module/module1.ko", |
| }, |
| Content: []byte("content"), |
| }, |
| }) |
| |
| var cfg gcs.GCSConfig |
| err = cfg.Init(ctx, "gs://my-bucket/path/to/module", server.Client()) |
| if err != nil { |
| t.Fatalf("Failed to initialize gcs config: %v", err) |
| } |
| moduleFiles := []string{"module1.ko", "skip.ko"} |
| |
| want := []string{fmt.Sprintf("%s/module1.ko", tmpDir)} |
| got, err := DownloadModules(ctx, &cfg, moduleFiles, tmpDir, false) |
| if err != nil { |
| t.Errorf("TestDownloadModulesSuccessful: error: %v", err) |
| } |
| if !reflect.DeepEqual(want, got) { |
| t.Errorf("TestDownloadKernelModuleSuccessful: expected module paths: %s\t got module paths: %s", want, got) |
| } |
| |
| } |
| |
| func TestDownloadModulesRecursivelySuccessful(t *testing.T) { |
| ctx := context.Background() |
| tmpDir, err := os.MkdirTemp("", "test-gcs") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir: %v", err) |
| } |
| defer os.RemoveAll(tmpDir) |
| |
| server := fakestorage.NewServer( |
| []fakestorage.Object{ |
| {ObjectAttrs: fakestorage.ObjectAttrs{ |
| BucketName: "my-bucket", Name: "path/to/module/a.ko", |
| }, |
| Content: []byte("content"), |
| }, |
| {ObjectAttrs: fakestorage.ObjectAttrs{ |
| BucketName: "my-bucket", Name: "path/to/module/b/b.ko", |
| }, |
| Content: []byte("content"), |
| }, |
| {ObjectAttrs: fakestorage.ObjectAttrs{ |
| BucketName: "my-bucket", Name: "path/to/module/c.ko", |
| }, |
| Content: []byte("content"), |
| }, |
| {ObjectAttrs: fakestorage.ObjectAttrs{ |
| BucketName: "my-bucket", Name: "path/to/module/d", |
| }, |
| Content: []byte("not module"), |
| }, |
| }) |
| |
| defer server.Stop() |
| var cfg gcs.GCSConfig |
| err = cfg.Init(ctx, "gs://my-bucket/path/to/module", server.Client()) |
| if err != nil { |
| t.Fatalf("Failed to initialize gcs config: %v", err) |
| } |
| got, err := DownloadModules(ctx, &cfg, []string{}, tmpDir, true) |
| if err != nil { |
| t.Errorf("TestDownloadAllKernelModulesSuccessful: failed to download module: %v", err) |
| } |
| want := []string{filepath.Join(tmpDir, "a.ko"), filepath.Join(tmpDir, "b/b.ko"), filepath.Join(tmpDir, "c.ko")} |
| |
| if !reflect.DeepEqual(got, want) { |
| t.Errorf("TestDownloadModulesRecursivelySuccessful: expected path: %s\t got path: %s", want, got) |
| } |
| } |
| |
| func TestRetrieveModulePaths(t *testing.T) { |
| tmpDir, err := os.MkdirTemp("", "test-gcs") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir (%s): %v", tmpDir, err) |
| } |
| defer os.RemoveAll(tmpDir) |
| subdir, err := os.MkdirTemp(tmpDir, "sub-test-gcs") |
| if err != nil { |
| t.Fatalf("Failed to create temp dir (%s): %v", subdir, err) |
| } |
| dsts := []string{filepath.Join(tmpDir, "module1.ko"), filepath.Join(subdir, "module2.ko")} |
| for _, dst := range dsts { |
| f, err := os.Create(dst) |
| f.Close() |
| if err != nil { |
| t.Fatalf("Failed to file (%s): %v", dst, err) |
| } |
| } |
| |
| tests := []struct { |
| desc string |
| recursive bool |
| want []string |
| }{ |
| { |
| desc: "Returns all module files in immediate directory.", |
| want: []string{dsts[0]}, |
| }, |
| { |
| desc: "Returns all module files in directory and subdirectory recursively.", |
| recursive: true, |
| want: dsts, |
| }, |
| } |
| for _, test := range tests { |
| t.Run(test.desc, func(t *testing.T) { |
| var modPaths []string |
| got, err := retrieveModulePaths(tmpDir, modPaths, test.recursive) |
| |
| if err != nil { |
| t.Errorf("TestRetrieveModulePaths(%s): error: %v", test.desc, err) |
| } |
| |
| if !reflect.DeepEqual(got, test.want) { |
| t.Errorf("TestRetrieveModulePaths(%s): expected module paths: %s\t got module paths: %s", test.desc, test.want, got) |
| } |
| }) |
| |
| } |
| } |