package main import ( "context" "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" "os" "os/exec" "path/filepath" "testing" "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" ) func TestVerifySignature_Valid(t *testing.T) { secret := "mysecret" body := "{\"message\":\"example\"}" // Compute the expected signature for the valid scenario. mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(body)) expectedSig := hex.EncodeToString(mac.Sum(nil)) // Prepare the signature header in the "sha256=" format. signatureHeader := "sha256=" + expectedSig if !verifySignature(secret, body, signatureHeader) { t.Errorf("Expected true for valid signature, got false") } } func TestVerifySignature_InvalidSignature(t *testing.T) { secret := "mysecret" body := "{\"message\":\"example\"}" // Use an intentionally incorrect signature. signatureHeader := "sha256=invalidsignature" if verifySignature(secret, body, signatureHeader) { t.Errorf("Expected false for an invalid signature, but got true") } } func TestVerifySignature_MissingPrefix(t *testing.T) { secret := "mysecret" body := "{\"message\":\"example\"}" // Provide a header that does not start with "sha256=" signatureHeader := "invalidprefix" if verifySignature(secret, body, signatureHeader) { t.Errorf("Expected false when header is missing the required prefix, got true") } } func TestVerifySignature_EmptyHeader(t *testing.T) { secret := "mysecret" body := "{\"message\":\"example\"}" signatureHeader := "" if verifySignature(secret, body, signatureHeader) { t.Errorf("Expected false when header is empty, got true") } } func TestLoadConfig_Success(t *testing.T) { // Set up environment variables for the test. os.Setenv("REPO_URL", "https://example.com/repo.git") os.Setenv("REPO_BRANCH", "main") os.Setenv("S3_BUCKET", "my-s3-bucket") os.Setenv("S3_KEY", "source.zip") os.Setenv("AWS_REGION", "ap-northeast-1") // Call the function. cfg, err := loadConfig() if err != nil { t.Fatalf("expected no error, got %v", err) } // Validate the configuration values. if cfg.RepoURL != "https://example.com/repo.git" { t.Errorf("unexpected RepoURL: got %s, want %s", cfg.RepoURL, "https://example.com/repo.git") } if cfg.RepoBranch != "main" { t.Errorf("unexpected RepoBranch: got %s, want %s", cfg.RepoBranch, "main") } if cfg.S3Bucket != "my-s3-bucket" { t.Errorf("unexpected S3Bucket: got %s, want %s", cfg.S3Bucket, "my-s3-bucket") } if cfg.S3Key != "source.zip" { t.Errorf("unexpected S3Key: got %s, want %s", cfg.S3Key, "source.zip") } if cfg.AWSRegion != "ap-northeast-1" { t.Errorf("unexpected AWSRegion: got %s, want %s", cfg.AWSRegion, "ap-northeast-1") } } func TestLoadConfig_MissingRepoURL(t *testing.T) { // Clear the REPO_URL environment variable. os.Unsetenv("REPO_URL") // Optionally, set up other required variables. os.Setenv("S3_BUCKET", "my-s3-bucket") // Call the function. _, err := loadConfig() if err == nil { t.Fatal("expected an error due to missing REPO_URL, got nil") } } func TestLoadConfig_MissingS3Bucket(t *testing.T) { // Clear the S3_BUCKET environment variable. os.Unsetenv("S3_BUCKET") // Optionally, set up other required variables. os.Setenv("REPO_URL", "https://example.com/repo.git") // Call the function. _, err := loadConfig() if err == nil { t.Fatal("expected an error due to missing S3_BUCKET, got nil") } } // TestHelperProcess is not a real test. It is invoked as a helper process // when our fake command runner is used. func TestHelperProcess(t *testing.T) { if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { // If the variable is not set, this function should do nothing. return } // If GO_EXIT_STATUS is set, convert it to an integer. if exitStatus := os.Getenv("GO_EXIT_STATUS"); exitStatus != "" { // You can exit with this status if it's nonzero. // For example, if it's "1", then this simulates a failing command. os.Exit(1) } // Otherwise, simulate success. os.Exit(0) } // fakeExecCommand returns a function that simulates exec.Command. // The success parameter indicates whether the command should succeed. func fakeExecCommand(success bool) func(name string, arg ...string) *exec.Cmd { return func(name string, arg ...string) *exec.Cmd { // We simulate the command by re-executing the test binary with special flags. // The "--" signals the end of flags for our helper. cs := []string{"-test.run=TestHelperProcess", "--", name} cs = append(cs, arg...) cmd := exec.Command(os.Args[0], cs...) // Set an env variable that tells our TestHelperProcess to run. cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} if !success { // Set a value to indicate failure. Our helper can inspect this if desired, // or we can simply exit with a non-zero status. cmd.Env = append(cmd.Env, "GO_EXIT_STATUS=1") } return cmd } } func TestCloneRepository_Success(t *testing.T) { // Override commandRunner to simulate a successful git clone. originalCommandRunner := commandRunner commandRunner = fakeExecCommand(true) defer func() { commandRunner = originalCommandRunner }() // Use a temporary directory for testing. tempDir := t.TempDir() // Call cloneRepository. err := cloneRepository(context.Background(), "https://example.com/repo.git", "main", tempDir) if err != nil { t.Fatalf("expected success, got error: %v", err) } } func TestCloneRepository_Failure(t *testing.T) { // Override commandRunner to simulate a failing git clone. originalCommandRunner := commandRunner commandRunner = fakeExecCommand(false) defer func() { commandRunner = originalCommandRunner }() tempDir := t.TempDir() // Call cloneRepository expecting an error. err := cloneRepository(context.Background(), "https://example.com/repo.git", "main", tempDir) if err == nil { t.Fatal("expected an error, got nil") } } // TestCreateZipArchive_Success simulates a successful zip creation. func TestCreateZipArchive_Success(t *testing.T) { // Override the global commandRunner with our fake that simulates success. originalCommandRunner := commandRunner commandRunner = fakeExecCommand(true) defer func() { commandRunner = originalCommandRunner }() // Use t.TempDir to create a temporary directory simulating the repo directory. tempDir := t.TempDir() // Define a zip file path within the temp directory. zipFilePath := filepath.Join(tempDir, "source.zip") // Call createZipArchive. if err := createZipArchive(context.Background(), tempDir, zipFilePath); err != nil { t.Fatalf("expected success, got error: %v", err) } } // TestCreateZipArchive_Failure simulates a failing zip creation. func TestCreateZipArchive_Failure(t *testing.T) { // Override commandRunner to simulate a command failure. originalCommandRunner := commandRunner commandRunner = fakeExecCommand(false) defer func() { commandRunner = originalCommandRunner }() tempDir := t.TempDir() zipFilePath := filepath.Join(tempDir, "source.zip") // Call createZipArchive and expect an error. if err := createZipArchive(context.Background(), tempDir, zipFilePath); err == nil { t.Fatal("expected an error, got nil") } } // fakeUploader implements the Uploader interface. type fakeUploader struct { success bool } func (f *fakeUploader) Upload(ctx context.Context, input *s3.PutObjectInput, opts ...func(*manager.Uploader)) (*manager.UploadOutput, error) { if f.success { // Simulate a successful upload with a fake location. return &manager.UploadOutput{Location: "http://fake-s3/uploaded-file"}, nil } // Simulate a failure. return nil, fmt.Errorf("fake upload error") } func TestUploadToS3WithUploader_Success(t *testing.T) { ctx := context.Background() // Create a temporary directory and file to act as the ZIP file. tempDir := t.TempDir() zipFilePath := filepath.Join(tempDir, "source.zip") content := []byte("dummy zip content") if err := os.WriteFile(zipFilePath, content, 0644); err != nil { t.Fatalf("failed to create temp zip file: %v", err) } // Create a fake uploader that simulates success. u := &fakeUploader{success: true} err := uploadToS3WithUploader(ctx, zipFilePath, "fake-bucket", "source.zip", u) if err != nil { t.Fatalf("expected success, got error: %v", err) } } func TestUploadToS3WithUploader_Failure(t *testing.T) { ctx := context.Background() tempDir := t.TempDir() zipFilePath := filepath.Join(tempDir, "source.zip") content := []byte("dummy zip content") if err := os.WriteFile(zipFilePath, content, 0644); err != nil { t.Fatalf("failed to create temp zip file: %v", err) } // Create a fake uploader that simulates a failure. u := &fakeUploader{success: false} err := uploadToS3WithUploader(ctx, zipFilePath, "fake-bucket", "source.zip", u) if err == nil { t.Fatal("expected an error, got nil") } }