Skip to content

Commit 4015bc4

Browse files
committed
test: cover drive downloads and gmail helpers
1 parent c6e1733 commit 4015bc4

File tree

4 files changed

+189
-2
lines changed

4 files changed

+189
-2
lines changed

internal/cmd/drive.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -872,10 +872,10 @@ func downloadDriveFile(ctx context.Context, svc *drive.Service, meta *drive.File
872872
if isGoogleDoc {
873873
exportMimeType := driveExportMimeType(meta.MimeType)
874874
outPath = replaceExt(destPath, driveExportExtension(exportMimeType))
875-
resp, err = svc.Files.Export(meta.Id, exportMimeType).Context(ctx).Download()
875+
resp, err = driveExportDownload(ctx, svc, meta.Id, exportMimeType)
876876
} else {
877877
outPath = destPath
878-
resp, err = svc.Files.Get(meta.Id).SupportsAllDrives(true).Context(ctx).Download()
878+
resp, err = driveDownload(ctx, svc, meta.Id)
879879
}
880880
if err != nil {
881881
return "", 0, err
@@ -900,6 +900,14 @@ func downloadDriveFile(ctx context.Context, svc *drive.Service, meta *drive.File
900900
return outPath, n, nil
901901
}
902902

903+
var driveDownload = func(ctx context.Context, svc *drive.Service, fileID string) (*http.Response, error) {
904+
return svc.Files.Get(fileID).SupportsAllDrives(true).Context(ctx).Download()
905+
}
906+
907+
var driveExportDownload = func(ctx context.Context, svc *drive.Service, fileID string, mimeType string) (*http.Response, error) {
908+
return svc.Files.Export(fileID, mimeType).Context(ctx).Download()
909+
}
910+
903911
func replaceExt(path string, ext string) string {
904912
base := strings.TrimSuffix(path, filepath.Ext(path))
905913
return base + ext
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"io"
6+
"net/http"
7+
"net/http/httptest"
8+
"os"
9+
"path/filepath"
10+
"strings"
11+
"testing"
12+
13+
"google.golang.org/api/drive/v3"
14+
"google.golang.org/api/option"
15+
)
16+
17+
func TestDownloadDriveFile_NonGoogleDoc(t *testing.T) {
18+
body := "hello"
19+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20+
// Files.Get(...).Download hits /drive/v3/files/{id}?alt=media
21+
if !(strings.Contains(r.URL.Path, "/files/") && r.URL.Query().Get("alt") == "media") {
22+
http.NotFound(w, r)
23+
return
24+
}
25+
w.WriteHeader(http.StatusOK)
26+
_, _ = io.WriteString(w, body)
27+
}))
28+
defer srv.Close()
29+
30+
svc, err := drive.NewService(context.Background(),
31+
option.WithoutAuthentication(),
32+
option.WithHTTPClient(srv.Client()),
33+
option.WithEndpoint(srv.URL+"/"),
34+
)
35+
if err != nil {
36+
t.Fatalf("NewService: %v", err)
37+
}
38+
39+
tmp := t.TempDir()
40+
dest := filepath.Join(tmp, "file.bin")
41+
outPath, n, err := downloadDriveFile(context.Background(), svc, &drive.File{Id: "id1", MimeType: "application/pdf"}, dest)
42+
if err != nil {
43+
t.Fatalf("downloadDriveFile: %v", err)
44+
}
45+
if outPath != dest {
46+
t.Fatalf("unexpected outPath: %q", outPath)
47+
}
48+
if n != int64(len(body)) {
49+
t.Fatalf("unexpected n: %d", n)
50+
}
51+
b, err := os.ReadFile(dest)
52+
if err != nil {
53+
t.Fatalf("read: %v", err)
54+
}
55+
if string(b) != body {
56+
t.Fatalf("unexpected body: %q", string(b))
57+
}
58+
}
59+
60+
func TestDownloadDriveFile_GoogleDocExport(t *testing.T) {
61+
body := "exported"
62+
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
63+
// Files.Export(...).Download hits /drive/v3/files/{id}/export?mimeType=...
64+
if !(strings.Contains(r.URL.Path, "/export") && strings.Contains(r.URL.Path, "/files/")) {
65+
http.NotFound(w, r)
66+
return
67+
}
68+
w.WriteHeader(http.StatusOK)
69+
_, _ = io.WriteString(w, body)
70+
}))
71+
defer srv.Close()
72+
73+
svc, err := drive.NewService(context.Background(),
74+
option.WithoutAuthentication(),
75+
option.WithHTTPClient(srv.Client()),
76+
option.WithEndpoint(srv.URL+"/"),
77+
)
78+
if err != nil {
79+
t.Fatalf("NewService: %v", err)
80+
}
81+
82+
tmp := t.TempDir()
83+
dest := filepath.Join(tmp, "doc.txt")
84+
outPath, n, err := downloadDriveFile(context.Background(), svc, &drive.File{Id: "id1", MimeType: "application/vnd.google-apps.document"}, dest)
85+
if err != nil {
86+
t.Fatalf("downloadDriveFile: %v", err)
87+
}
88+
if !strings.HasSuffix(outPath, ".pdf") {
89+
t.Fatalf("expected pdf outPath, got: %q", outPath)
90+
}
91+
if n != int64(len(body)) {
92+
t.Fatalf("unexpected n: %d", n)
93+
}
94+
b, err := os.ReadFile(outPath)
95+
if err != nil {
96+
t.Fatalf("read: %v", err)
97+
}
98+
if string(b) != body {
99+
t.Fatalf("unexpected body: %q", string(b))
100+
}
101+
}
102+
103+
func TestDownloadDriveFile_HTTPError(t *testing.T) {
104+
orig := driveDownload
105+
t.Cleanup(func() { driveDownload = orig })
106+
driveDownload = func(context.Context, *drive.Service, string) (*http.Response, error) {
107+
return &http.Response{
108+
Status: "403 Forbidden",
109+
StatusCode: http.StatusForbidden,
110+
Body: io.NopCloser(strings.NewReader("nope\n")),
111+
}, nil
112+
}
113+
114+
tmp := t.TempDir()
115+
dest := filepath.Join(tmp, "file.bin")
116+
_, _, err := downloadDriveFile(context.Background(), &drive.Service{}, &drive.File{Id: "id1", MimeType: "application/pdf"}, dest)
117+
if err == nil {
118+
t.Fatalf("expected error")
119+
}
120+
if !strings.Contains(err.Error(), "download failed") || !strings.Contains(err.Error(), "nope") {
121+
t.Fatalf("unexpected error: %v", err)
122+
}
123+
}
124+
125+
func TestDownloadDriveFile_CreateError(t *testing.T) {
126+
orig := driveDownload
127+
t.Cleanup(func() { driveDownload = orig })
128+
driveDownload = func(context.Context, *drive.Service, string) (*http.Response, error) {
129+
return &http.Response{
130+
Status: "200 OK",
131+
StatusCode: http.StatusOK,
132+
Body: io.NopCloser(strings.NewReader("x")),
133+
}, nil
134+
}
135+
136+
tmp := t.TempDir()
137+
dest := filepath.Join(tmp, "no-such-dir", "file.bin")
138+
_, _, err := downloadDriveFile(context.Background(), &drive.Service{}, &drive.File{Id: "id1", MimeType: "application/pdf"}, dest)
139+
if err == nil {
140+
t.Fatalf("expected error")
141+
}
142+
}

internal/cmd/gmail_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,16 @@ func TestFormatGmailDate(t *testing.T) {
3939
t.Fatalf("unexpected: %q", got)
4040
}
4141
}
42+
43+
func TestFirstMessage(t *testing.T) {
44+
if firstMessage(nil) != nil {
45+
t.Fatalf("expected nil")
46+
}
47+
if firstMessage(&gmail.Thread{}) != nil {
48+
t.Fatalf("expected nil")
49+
}
50+
m := &gmail.Message{Id: "m1"}
51+
if got := firstMessage(&gmail.Thread{Messages: []*gmail.Message{m}}); got == nil || got.Id != "m1" {
52+
t.Fatalf("unexpected: %#v", got)
53+
}
54+
}

internal/googleapi/client_more_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,27 @@ func TestOptionsForAccountScopes_HappyPath(t *testing.T) {
135135
t.Fatalf("expected client options")
136136
}
137137
}
138+
139+
func TestOptionsForAccount_HappyPath(t *testing.T) {
140+
origRead := readClientCredentials
141+
origOpen := openSecretsStore
142+
t.Cleanup(func() {
143+
readClientCredentials = origRead
144+
openSecretsStore = origOpen
145+
})
146+
147+
readClientCredentials = func() (config.ClientCredentials, error) {
148+
return config.ClientCredentials{ClientID: "id", ClientSecret: "secret"}, nil
149+
}
150+
openSecretsStore = func() (secrets.Store, error) {
151+
return &stubStore{tok: secrets.Token{Email: "a@b.com", RefreshToken: "rt"}}, nil
152+
}
153+
154+
opts, err := optionsForAccount(context.Background(), googleauth.ServiceDrive, "a@b.com")
155+
if err != nil {
156+
t.Fatalf("unexpected err: %v", err)
157+
}
158+
if len(opts) == 0 {
159+
t.Fatalf("expected client options")
160+
}
161+
}

0 commit comments

Comments
 (0)