1// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package build
16
17import (
18	"errors"
19	"io/ioutil"
20	"os"
21	"path/filepath"
22	"reflect"
23	"sort"
24	"strconv"
25	"strings"
26	"testing"
27	"time"
28
29	"android/soong/ui/logger"
30)
31
32func TestPruneMetricsFiles(t *testing.T) {
33	rootDir := t.TempDir()
34
35	dirs := []string{
36		filepath.Join(rootDir, "d1"),
37		filepath.Join(rootDir, "d1", "d2"),
38		filepath.Join(rootDir, "d1", "d2", "d3"),
39	}
40
41	files := []string{
42		filepath.Join(rootDir, "d1", "f1"),
43		filepath.Join(rootDir, "d1", "d2", "f1"),
44		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
45	}
46
47	for _, d := range dirs {
48		if err := os.MkdirAll(d, 0777); err != nil {
49			t.Fatalf("got %v, expecting nil error for making directory %q", err, d)
50		}
51	}
52
53	for _, f := range files {
54		if err := ioutil.WriteFile(f, []byte{}, 0777); err != nil {
55			t.Fatalf("got %v, expecting nil error on writing file %q", err, f)
56		}
57	}
58
59	want := []string{
60		filepath.Join(rootDir, "d1", "f1"),
61		filepath.Join(rootDir, "d1", "d2", "f1"),
62		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
63	}
64
65	got := pruneMetricsFiles([]string{rootDir})
66
67	sort.Strings(got)
68	sort.Strings(want)
69
70	if !reflect.DeepEqual(got, want) {
71		t.Errorf("got %q, want %q after pruning metrics files", got, want)
72	}
73}
74
75func TestUploadMetrics(t *testing.T) {
76	ctx := testContext()
77	tests := []struct {
78		description string
79		uploader    string
80		createFiles bool
81		files       []string
82	}{{
83		description: "ANDROID_ENABLE_METRICS_UPLOAD not set",
84	}, {
85		description: "no metrics files to upload",
86		uploader:    "fake",
87	}, {
88		description: "non-existent metrics files no upload",
89		uploader:    "fake",
90		files:       []string{"metrics_file_1", "metrics_file_2", "metrics_file_3"},
91	}, {
92		description: "trigger upload",
93		uploader:    "echo",
94		createFiles: true,
95		files:       []string{"metrics_file_1", "metrics_file_2"},
96	}}
97
98	for _, tt := range tests {
99		t.Run(tt.description, func(t *testing.T) {
100			defer logger.Recover(func(err error) {
101				t.Fatalf("got unexpected error: %v", err)
102			})
103
104			outDir, err := ioutil.TempDir("", "")
105			if err != nil {
106				t.Fatalf("failed to create out directory: %v", outDir)
107			}
108			defer os.RemoveAll(outDir)
109
110			// Supply our own tmpDir to delete the temp dir once the test is done.
111			orgTmpDir := tmpDir
112			tmpDir = func(string, string) (string, error) {
113				retDir := filepath.Join(outDir, "tmp_upload_dir")
114				if err := os.Mkdir(retDir, 0755); err != nil {
115					t.Fatalf("failed to create temporary directory %q: %v", retDir, err)
116				}
117				return retDir, nil
118			}
119			defer func() { tmpDir = orgTmpDir }()
120
121			metricsUploadDir := filepath.Join(outDir, ".metrics_uploader")
122			if err := os.Mkdir(metricsUploadDir, 0755); err != nil {
123				t.Fatalf("failed to create %q directory for oauth valid check: %v", metricsUploadDir, err)
124			}
125
126			var metricsFiles []string
127			if tt.createFiles {
128				for _, f := range tt.files {
129					filename := filepath.Join(outDir, f)
130					metricsFiles = append(metricsFiles, filename)
131					if err := ioutil.WriteFile(filename, []byte("test file"), 0644); err != nil {
132						t.Fatalf("failed to create a fake metrics file %q for uploading: %v", filename, err)
133					}
134				}
135			}
136
137			config := Config{&configImpl{
138				environ: &Environment{
139					"OUT_DIR=" + outDir,
140					"ANDROID_ENABLE_METRICS_UPLOAD=" + tt.uploader,
141				},
142				buildDateTime: strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10),
143			}}
144
145			UploadMetrics(ctx, config, false, time.Now(), metricsFiles...)
146		})
147	}
148}
149
150func TestUploadMetricsErrors(t *testing.T) {
151	ctx := testContext()
152	tests := []struct {
153		description string
154		tmpDir      string
155		tmpDirErr   error
156		expectedErr string
157	}{{
158		description: "getTmpDir returned error",
159		tmpDirErr:   errors.New("getTmpDir failed"),
160		expectedErr: "getTmpDir failed",
161	}, {
162		description: "copyFile operation error",
163		tmpDir:      "/fake_dir",
164		expectedErr: "failed to copy",
165	}}
166
167	for _, tt := range tests {
168		t.Run(tt.description, func(t *testing.T) {
169			defer logger.Recover(func(err error) {
170				got := err.Error()
171				if !strings.Contains(got, tt.expectedErr) {
172					t.Errorf("got %q, want %q to be contained in error", got, tt.expectedErr)
173				}
174			})
175
176			outDir, err := ioutil.TempDir("", "")
177			if err != nil {
178				t.Fatalf("failed to create out directory: %v", outDir)
179			}
180			defer os.RemoveAll(outDir)
181
182			orgTmpDir := tmpDir
183			tmpDir = func(string, string) (string, error) {
184				return tt.tmpDir, tt.tmpDirErr
185			}
186			defer func() { tmpDir = orgTmpDir }()
187
188			metricsFile := filepath.Join(outDir, "metrics_file_1")
189			if err := ioutil.WriteFile(metricsFile, []byte("test file"), 0644); err != nil {
190				t.Fatalf("failed to create a fake metrics file %q for uploading: %v", metricsFile, err)
191			}
192
193			config := Config{&configImpl{
194				environ: &Environment{
195					"ANDROID_ENABLE_METRICS_UPLOAD=fake",
196					"OUT_DIR=/bad",
197				}}}
198
199			UploadMetrics(ctx, config, true, time.Now(), metricsFile)
200			t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
201		})
202	}
203}
204