| // Copyright 2026 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package androidtools |
| |
| import ( |
| "context" |
| "testing" |
| "time" |
| |
| "github.com/golang/mock/gomock" |
| "google.golang.org/grpc" |
| |
| "go.chromium.org/chromiumos/config/go/test/api" |
| "go.chromium.org/luci/common/errors" |
| |
| "go.chromium.org/infra/cros/lib/provisions/common" |
| "go.chromium.org/infra/cros/lib/provisions/common/mocks" |
| ) |
| |
| func TestDownloadFileLocally(t *testing.T) { |
| t.Parallel() |
| ctx := context.Background() |
| ctrl := gomock.NewController(t) |
| defer ctrl.Finish() |
| |
| timeout := 1 * time.Minute |
| sourcePath := "http://example.com/file.zip" |
| distPath := "/tmp/file.zip" |
| |
| mockRun := func(ctx context.Context, timeout time.Duration, cmd string, args ...string) (common.Response, error) { |
| if cmd != "curl" { |
| t.Errorf("Expected 'curl', got %q", cmd) |
| } |
| foundOutput := false |
| for i, arg := range args { |
| if arg == "--output" && i+1 < len(args) && args[i+1] == distPath { |
| foundOutput = true |
| break |
| } |
| } |
| if !foundOutput { |
| t.Errorf("Expected --output %s in args: %v", distPath, args) |
| } |
| mockResp := mocks.NewMockResponse(ctrl) |
| mockResp.EXPECT().GetStdout().Return([]byte("success")) |
| mockResp.EXPECT().GetStderr().Return([]byte("")) |
| return mockResp, nil |
| } |
| |
| err := downloadFileLocally(ctx, mockRun, timeout, sourcePath, distPath) |
| if err != nil { |
| t.Errorf("downloadFileLocally() returned an unexpected error: %v", err) |
| } |
| } |
| |
| func TestDownloadFileLocally_Errors(t *testing.T) { |
| t.Parallel() |
| ctx := context.Background() |
| ctrl := gomock.NewController(t) |
| defer ctrl.Finish() |
| |
| timeout := 1 * time.Minute |
| sourcePath := "http://example.com/file.zip" |
| distPath := "/tmp/file.zip" |
| |
| tests := []struct { |
| name string |
| runner common.RunnerFunc |
| wantErr bool |
| }{ |
| { |
| name: "nil runner", |
| runner: nil, |
| wantErr: true, |
| }, |
| { |
| name: "runner error", |
| runner: func(context.Context, time.Duration, string, ...string) (common.Response, error) { |
| return nil, errors.New("runner failed") |
| }, |
| wantErr: true, |
| }, |
| { |
| name: "curl non-zero exit", |
| runner: func(ctx context.Context, timeout time.Duration, cmd string, args ...string) (common.Response, error) { |
| return nil, errors.New("exit code 1") // common.Run delegates error for non-zero exit |
| }, |
| wantErr: true, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| err := downloadFileLocally(ctx, tt.runner, timeout, sourcePath, distPath) |
| if tt.wantErr != (err != nil) { |
| t.Errorf("downloadFileLocally() error = %v, wantErr %v", err, tt.wantErr) |
| } |
| }) |
| } |
| } |
| |
| type mockToolsServiceClient struct { |
| api.ToolsServiceClient |
| downloadFileFunc func(ctx context.Context, in *api.DownloadFileRequest, opts ...grpc.CallOption) (*api.DownloadFileResponse, error) |
| } |
| |
| func (m *mockToolsServiceClient) DownloadFile(ctx context.Context, in *api.DownloadFileRequest, opts ...grpc.CallOption) (*api.DownloadFileResponse, error) { |
| if m.downloadFileFunc != nil { |
| return m.downloadFileFunc(ctx, in, opts...) |
| } |
| return nil, nil |
| } |
| |
| func TestDownloadFileGRPC(t *testing.T) { |
| t.Parallel() |
| ctx := context.Background() |
| timeout := 1 * time.Minute |
| sourcePath := "http://example.com/file.zip" |
| distPath := "/tmp/file.zip" |
| |
| client := &mockToolsServiceClient{ |
| downloadFileFunc: func(ctx context.Context, in *api.DownloadFileRequest, opts ...grpc.CallOption) (*api.DownloadFileResponse, error) { |
| if in.GetUrl() != sourcePath { |
| t.Errorf("Expected URL %q, got %q", sourcePath, in.GetUrl()) |
| } |
| if in.GetDestinationPath() != distPath { |
| t.Errorf("Expected destination path %q, got %q", distPath, in.GetDestinationPath()) |
| } |
| return &api.DownloadFileResponse{ |
| DestinationPath: distPath, |
| }, nil |
| }, |
| } |
| |
| err := downloadFileGRPC(ctx, client, timeout, sourcePath, distPath) |
| if err != nil { |
| t.Errorf("downloadFileGRPC() returned unexpected error: %v", err) |
| } |
| } |
| |
| func TestDownloadFileGRPC_Errors(t *testing.T) { |
| t.Parallel() |
| ctx := context.Background() |
| timeout := 1 * time.Minute |
| sourcePath := "http://example.com/file.zip" |
| distPath := "/tmp/file.zip" |
| |
| tests := []struct { |
| name string |
| client api.ToolsServiceClient |
| wantErr bool |
| }{ |
| { |
| name: "nil client", |
| client: nil, |
| wantErr: true, |
| }, |
| { |
| name: "client error", |
| client: &mockToolsServiceClient{ |
| downloadFileFunc: func(ctx context.Context, in *api.DownloadFileRequest, opts ...grpc.CallOption) (*api.DownloadFileResponse, error) { |
| return nil, errors.New("gRPC error") |
| }, |
| }, |
| wantErr: true, |
| }, |
| } |
| |
| for _, tt := range tests { |
| t.Run(tt.name, func(t *testing.T) { |
| err := downloadFileGRPC(ctx, tt.client, timeout, sourcePath, distPath) |
| if tt.wantErr != (err != nil) { |
| t.Errorf("downloadFileGRPC() error = %v, wantErr %v", err, tt.wantErr) |
| } |
| }) |
| } |
| } |