github.com/ubuntu/ubuntu-report@v1.7.4-0.20240410144652-96f37d845fac/pkg/sysmetrics/api_test.go (about)

     1  package sysmetrics_test
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"os"
    10  	"path/filepath"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/ubuntu/ubuntu-report/internal/helper"
    15  	"github.com/ubuntu/ubuntu-report/pkg/sysmetrics"
    16  )
    17  
    18  func TestCollect(t *testing.T) {
    19  	t.Parallel()
    20  
    21  	data, err := sysmetrics.Collect()
    22  
    23  	if err != nil {
    24  		t.Fatal("we didn't expect an error and got one", err)
    25  	}
    26  
    27  	if !strings.Contains(string(data), sysmetrics.ExpectedReportItem) {
    28  		t.Errorf("we expected at least %s in output, got: '%s", sysmetrics.ExpectedReportItem, string(data))
    29  	}
    30  }
    31  
    32  func TestSendReport(t *testing.T) {
    33  	// we change current path and env variable: not parallelizable tests
    34  	helper.SkipIfShort(t)
    35  
    36  	testCases := []struct {
    37  		name         string
    38  		alwaysReport bool
    39  
    40  		shouldHitServer bool
    41  		wantErr         bool
    42  	}{
    43  		{"regular send", false, true, false},
    44  	}
    45  	for _, tc := range testCases {
    46  		tc := tc // capture range variable for parallel execution
    47  		t.Run(tc.name, func(t *testing.T) {
    48  			a := helper.Asserter{T: t}
    49  
    50  			out, tearDown := helper.TempDir(t)
    51  			defer tearDown()
    52  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
    53  			out = filepath.Join(out, "ubuntu-report")
    54  			// we don't really care where we hit for this API integration test, internal ones test it
    55  			// and we don't really control /etc/os-release version and id.
    56  			// Same for report file
    57  			serverHit := false
    58  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    59  				serverHit = true
    60  			}))
    61  			defer ts.Close()
    62  
    63  			err := sysmetrics.SendReport([]byte(fmt.Sprintf(`{ %s: "18.04" }`, sysmetrics.ExpectedReportItem)),
    64  				tc.alwaysReport, ts.URL)
    65  
    66  			a.CheckWantedErr(err, tc.wantErr)
    67  			a.Equal(serverHit, tc.shouldHitServer)
    68  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
    69  			data, err := ioutil.ReadFile(p)
    70  			if err != nil {
    71  				t.Fatalf("couldn't open report file %s", out)
    72  			}
    73  			d := string(data)
    74  			if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
    75  				t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.ExpectedReportItem, d)
    76  			}
    77  		})
    78  	}
    79  }
    80  func TestSendDecline(t *testing.T) {
    81  	// we change current path and env variable: not parallelizable tests
    82  	helper.SkipIfShort(t)
    83  
    84  	testCases := []struct {
    85  		name         string
    86  		alwaysReport bool
    87  
    88  		shouldHitServer bool
    89  		wantErr         bool
    90  	}{
    91  		{"regular send opt-out", false, true, false},
    92  	}
    93  	for _, tc := range testCases {
    94  		tc := tc // capture range variable for parallel execution
    95  		t.Run(tc.name, func(t *testing.T) {
    96  			a := helper.Asserter{T: t}
    97  
    98  			out, tearDown := helper.TempDir(t)
    99  			defer tearDown()
   100  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   101  			out = filepath.Join(out, "ubuntu-report")
   102  			// we don't really care where we hit for this API integration test, internal ones test it
   103  			// and we don't really control /etc/os-release version and id.
   104  			// Same for report file
   105  			serverHit := false
   106  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   107  				serverHit = true
   108  			}))
   109  			defer ts.Close()
   110  
   111  			err := sysmetrics.SendDecline(tc.alwaysReport, ts.URL)
   112  
   113  			if err != nil {
   114  				t.Fatal("we didn't expect getting an error, got:", err)
   115  			}
   116  
   117  			a.Equal(serverHit, tc.shouldHitServer)
   118  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   119  			data, err := ioutil.ReadFile(p)
   120  			if err != nil {
   121  				t.Fatalf("couldn't open report file %s", out)
   122  			}
   123  			d := string(data)
   124  			if !strings.Contains(d, sysmetrics.OptOutJSON) {
   125  				t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.OptOutJSON, d)
   126  			}
   127  		})
   128  	}
   129  }
   130  
   131  func TestSendReportTwice(t *testing.T) {
   132  	// we change current path and env variable: not parallelizable tests
   133  	helper.SkipIfShort(t)
   134  
   135  	testCases := []struct {
   136  		name         string
   137  		alwaysReport bool
   138  
   139  		wantErr bool
   140  	}{
   141  		{"fail report twice", false, true},
   142  		{"forcing report twice", true, false},
   143  	}
   144  	for _, tc := range testCases {
   145  		tc := tc // capture range variable for parallel execution
   146  		t.Run(tc.name, func(t *testing.T) {
   147  			a := helper.Asserter{T: t}
   148  
   149  			out, tearDown := helper.TempDir(t)
   150  			defer tearDown()
   151  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   152  			out = filepath.Join(out, "ubuntu-report")
   153  			// we don't really care where we hit for this API integration test, internal ones test it
   154  			// and we don't really control /etc/os-release version and id.
   155  			// Same for report file
   156  			serverHit := false
   157  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   158  				serverHit = true
   159  			}))
   160  			defer ts.Close()
   161  
   162  			// first call
   163  			err := sysmetrics.SendReport([]byte(fmt.Sprintf(`{ %s: "18.04" }`, sysmetrics.ExpectedReportItem)),
   164  				tc.alwaysReport, ts.URL)
   165  			if err != nil {
   166  				t.Fatal("we didn't expect getting an error, got:", err)
   167  			}
   168  			a.Equal(serverHit, true)
   169  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   170  			data, err := ioutil.ReadFile(p)
   171  			if err != nil {
   172  				t.Fatalf("couldn't open report file %s", out)
   173  			}
   174  			d := string(data)
   175  			if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
   176  				t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.ExpectedReportItem, d)
   177  			}
   178  
   179  			// scratch data file
   180  			if err != ioutil.WriteFile(p, []byte(""), 0644) {
   181  				t.Fatalf("couldn't reset %s: %v", p, err)
   182  			}
   183  
   184  			// second call, reset server
   185  			serverHit = false
   186  			err = sysmetrics.SendReport([]byte(fmt.Sprintf(`{ %s: "18.04" }`, sysmetrics.ExpectedReportItem)),
   187  				tc.alwaysReport, ts.URL)
   188  			a.CheckWantedErr(err, tc.wantErr)
   189  
   190  			a.Equal(serverHit, tc.alwaysReport)
   191  			// reread the same file
   192  			data, err = ioutil.ReadFile(p)
   193  			if err != nil {
   194  				t.Fatalf("couldn't open report file %s", out)
   195  			}
   196  			d = string(data)
   197  			switch tc.alwaysReport {
   198  			case true:
   199  				if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
   200  					t.Errorf("we expected to find %s in second report file, got: %s", sysmetrics.ExpectedReportItem, d)
   201  				}
   202  			case false:
   203  				if d != "" {
   204  					t.Errorf("we expected to have an untouched report file on second report, got: %s", d)
   205  				}
   206  			}
   207  
   208  		})
   209  	}
   210  }
   211  
   212  func TestSendDeclineTwice(t *testing.T) {
   213  	// we change current path and env variable: not parallelizable tests
   214  	helper.SkipIfShort(t)
   215  
   216  	testCases := []struct {
   217  		name         string
   218  		alwaysReport bool
   219  
   220  		wantErr bool
   221  	}{
   222  		{"fail decline twice", false, true},
   223  		{"forcing decline twice", true, false},
   224  	}
   225  	for _, tc := range testCases {
   226  		tc := tc // capture range variable for parallel execution
   227  		t.Run(tc.name, func(t *testing.T) {
   228  			a := helper.Asserter{T: t}
   229  
   230  			out, tearDown := helper.TempDir(t)
   231  			defer tearDown()
   232  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   233  			out = filepath.Join(out, "ubuntu-report")
   234  			// we don't really care where we hit for this API integration test, internal ones test it
   235  			// and we don't really control /etc/os-release version and id.
   236  			// Same for report file
   237  			serverHit := false
   238  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   239  				serverHit = true
   240  			}))
   241  			defer ts.Close()
   242  
   243  			// first call
   244  			err := sysmetrics.SendDecline(tc.alwaysReport, ts.URL)
   245  			if err != nil {
   246  				t.Fatal("we didn't expect getting an error, got:", err)
   247  			}
   248  			a.Equal(serverHit, true)
   249  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   250  			data, err := ioutil.ReadFile(p)
   251  			if err != nil {
   252  				t.Fatalf("couldn't open report file %s", out)
   253  			}
   254  			d := string(data)
   255  			if !strings.Contains(d, sysmetrics.OptOutJSON) {
   256  				t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.OptOutJSON, d)
   257  			}
   258  
   259  			// scratch data file
   260  			if err != ioutil.WriteFile(p, []byte(""), 0644) {
   261  				t.Fatalf("couldn't reset %s: %v", p, err)
   262  			}
   263  
   264  			// second call, reset server
   265  			serverHit = false
   266  			err = sysmetrics.SendDecline(tc.alwaysReport, ts.URL)
   267  			a.CheckWantedErr(err, tc.wantErr)
   268  
   269  			a.Equal(serverHit, tc.alwaysReport)
   270  			// reread the same file
   271  			data, err = ioutil.ReadFile(p)
   272  			if err != nil {
   273  				t.Fatalf("couldn't open report file %s", out)
   274  			}
   275  			d = string(data)
   276  			switch tc.alwaysReport {
   277  			case true:
   278  				if !strings.Contains(d, sysmetrics.OptOutJSON) {
   279  					t.Errorf("we expected to find %s in second report file, got: %s", sysmetrics.OptOutJSON, d)
   280  				}
   281  			case false:
   282  				if d != "" {
   283  					t.Errorf("we expected to have an untouched report file on second report, got: %s", d)
   284  				}
   285  			}
   286  
   287  		})
   288  	}
   289  }
   290  
   291  func TestNonInteractiveCollectAndSend(t *testing.T) {
   292  	// we change current path and env variable: not parallelizable tests
   293  	helper.SkipIfShort(t)
   294  
   295  	testCases := []struct {
   296  		name         string
   297  		r            sysmetrics.ReportType
   298  		alwaysReport bool
   299  
   300  		shouldHitServer bool
   301  		wantErr         bool
   302  	}{
   303  		{"regular report auto", sysmetrics.ReportAuto, false, true, false},
   304  		{"regular report opt-out", sysmetrics.ReportOptOut, false, true, false},
   305  	}
   306  	for _, tc := range testCases {
   307  		tc := tc // capture range variable for parallel execution
   308  		t.Run(tc.name, func(t *testing.T) {
   309  			a := helper.Asserter{T: t}
   310  
   311  			out, tearDown := helper.TempDir(t)
   312  			defer tearDown()
   313  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   314  			out = filepath.Join(out, "ubuntu-report")
   315  			// we don't really care where we hit for this API integration test, internal ones test it
   316  			// and we don't really control /etc/os-release version and id.
   317  			// Same for report file
   318  			serverHit := false
   319  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   320  				serverHit = true
   321  			}))
   322  			defer ts.Close()
   323  
   324  			err := sysmetrics.CollectAndSend(tc.r, tc.alwaysReport, ts.URL)
   325  
   326  			if err != nil {
   327  				t.Fatal("we didn't expect getting an error, got:", err)
   328  			}
   329  
   330  			a.Equal(serverHit, tc.shouldHitServer)
   331  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   332  			data, err := ioutil.ReadFile(p)
   333  			if err != nil {
   334  				t.Fatalf("couldn't open report file %s", out)
   335  			}
   336  			d := string(data)
   337  			switch tc.r {
   338  			case sysmetrics.ReportAuto:
   339  				if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
   340  					t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.ExpectedReportItem, d)
   341  				}
   342  			case sysmetrics.ReportOptOut:
   343  				if !strings.Contains(d, sysmetrics.OptOutJSON) {
   344  					t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.OptOutJSON, d)
   345  				}
   346  			}
   347  		})
   348  	}
   349  }
   350  
   351  func TestCollectAndSendTwice(t *testing.T) {
   352  	// we change current path and env variable: not parallelizable tests
   353  	helper.SkipIfShort(t)
   354  
   355  	testCases := []struct {
   356  		name         string
   357  		alwaysReport bool
   358  
   359  		wantErr bool
   360  	}{
   361  		{"fail report twice", false, true},
   362  		{"forcing report twice", true, false},
   363  	}
   364  	for _, tc := range testCases {
   365  		tc := tc // capture range variable for parallel execution
   366  		t.Run(tc.name, func(t *testing.T) {
   367  			a := helper.Asserter{T: t}
   368  
   369  			out, tearDown := helper.TempDir(t)
   370  			defer tearDown()
   371  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   372  			out = filepath.Join(out, "ubuntu-report")
   373  			// we don't really care where we hit for this API integration test, internal ones test it
   374  			// and we don't really control /etc/os-release version and id.
   375  			// Same for report file
   376  			serverHit := false
   377  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   378  				serverHit = true
   379  			}))
   380  			defer ts.Close()
   381  
   382  			// first call
   383  			err := sysmetrics.CollectAndSend(sysmetrics.ReportAuto, tc.alwaysReport, ts.URL)
   384  			if err != nil {
   385  				t.Fatal("we didn't expect getting an error, got:", err)
   386  			}
   387  			a.Equal(serverHit, true)
   388  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   389  			data, err := ioutil.ReadFile(p)
   390  			if err != nil {
   391  				t.Fatalf("couldn't open report file %s", out)
   392  			}
   393  			d := string(data)
   394  			if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
   395  				t.Errorf("we expected to find %s in report file, got: %s", sysmetrics.ExpectedReportItem, d)
   396  			}
   397  
   398  			// scratch data file
   399  			if err != ioutil.WriteFile(p, []byte(""), 0644) {
   400  				t.Fatalf("couldn't reset %s: %v", p, err)
   401  			}
   402  
   403  			// second call, reset server
   404  			serverHit = false
   405  			err = sysmetrics.CollectAndSend(sysmetrics.ReportAuto, tc.alwaysReport, ts.URL)
   406  			a.CheckWantedErr(err, tc.wantErr)
   407  
   408  			a.Equal(serverHit, tc.alwaysReport)
   409  			// reread the same file
   410  			data, err = ioutil.ReadFile(p)
   411  			if err != nil {
   412  				t.Fatalf("couldn't open report file %s", out)
   413  			}
   414  			d = string(data)
   415  			switch tc.alwaysReport {
   416  			case true:
   417  				if !strings.Contains(d, sysmetrics.ExpectedReportItem) {
   418  					t.Errorf("we expected to find %s in second report file, got: %s", sysmetrics.ExpectedReportItem, d)
   419  				}
   420  			case false:
   421  				if d != "" {
   422  					t.Errorf("we expected to have an untouched report file on second report, got: %s", d)
   423  				}
   424  			}
   425  
   426  		})
   427  	}
   428  }
   429  
   430  func TestInteractiveCollectAndSend(t *testing.T) {
   431  	// we change current path and env variable: not parallelizable tests
   432  	helper.SkipIfShort(t)
   433  
   434  	testCases := []struct {
   435  		name    string
   436  		answers []string
   437  
   438  		sendOnlyOptOutData bool
   439  		wantWriteAndUpload bool
   440  	}{
   441  		{"yes", []string{"yes"}, false, true},
   442  		{"y", []string{"y"}, false, true},
   443  		{"YES", []string{"YES"}, false, true},
   444  		{"Y", []string{"Y"}, false, true},
   445  		{"no", []string{"no"}, true, true},
   446  		{"n", []string{"n"}, true, true},
   447  		{"NO", []string{"NO"}, true, true},
   448  		{"n", []string{"N"}, true, true},
   449  		{"quit", []string{"quit"}, false, false},
   450  		{"q", []string{"q"}, false, false},
   451  		{"QUIT", []string{"QUIT"}, false, false},
   452  		{"Q", []string{"Q"}, false, false},
   453  		{"default-quit", []string{""}, false, false},
   454  		{"garbage-then-quit", []string{"garbage", "yesgarbage", "nogarbage", "quitgarbage", "Q"}, false, false},
   455  		{"ctrl-c-input", []string{"CTRL-C"}, false, false},
   456  	}
   457  	for _, tc := range testCases {
   458  		tc := tc // capture range variable for parallel execution
   459  		t.Run(tc.name, func(t *testing.T) {
   460  			a := helper.Asserter{T: t}
   461  
   462  			out, tearDown := helper.TempDir(t)
   463  			defer tearDown()
   464  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   465  			out = filepath.Join(out, "ubuntu-report")
   466  			// we don't really care where we hit for this API integration test, internal ones test it
   467  			// and we don't really control /etc/os-release version and id.
   468  			// Same for report file
   469  			serverHit := false
   470  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   471  				serverHit = true
   472  			}))
   473  			defer ts.Close()
   474  
   475  			stdout, tearDown := helper.CaptureStdout(t)
   476  			defer tearDown()
   477  			stdin, tearDown := helper.CaptureStdin(t)
   478  			defer tearDown()
   479  
   480  			cmdErrs := helper.RunFunctionWithTimeout(t, func() error { return sysmetrics.CollectAndSend(sysmetrics.ReportInteractive, false, ts.URL) })
   481  
   482  			gotJSONReport := false
   483  			answerIndex := 0
   484  			scanner := bufio.NewScanner(stdout)
   485  			scanner.Split(sysmetrics.ScanLinesOrQuestion)
   486  			for scanner.Scan() {
   487  				txt := scanner.Text()
   488  				// first, we should have a known element
   489  				if strings.Contains(txt, sysmetrics.ExpectedReportItem) {
   490  					gotJSONReport = true
   491  				}
   492  				if !strings.Contains(txt, "Do you agree to report this?") {
   493  					continue
   494  				}
   495  				a := tc.answers[answerIndex]
   496  				if a == "CTRL-C" {
   497  					stdin.Close()
   498  					break
   499  				} else {
   500  					stdin.Write([]byte(tc.answers[answerIndex] + "\n"))
   501  				}
   502  				answerIndex = answerIndex + 1
   503  				// all answers have be provided
   504  				if answerIndex >= len(tc.answers) {
   505  					stdin.Close()
   506  					break
   507  				}
   508  			}
   509  
   510  			if err := <-cmdErrs; err != nil {
   511  				t.Fatal("didn't expect to get an error, got:", err)
   512  			}
   513  			a.Equal(gotJSONReport, true)
   514  			a.Equal(serverHit, tc.wantWriteAndUpload)
   515  
   516  			if !tc.wantWriteAndUpload {
   517  				if _, err := os.Stat(filepath.Join(out, "ubuntu-report")); err == nil || (err != nil && !os.IsNotExist(err)) {
   518  					t.Fatal("we didn't want to get a report but we got one")
   519  				}
   520  				return
   521  			}
   522  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   523  			data, err := ioutil.ReadFile(p)
   524  			if err != nil {
   525  				t.Fatalf("couldn't open report file %s", out)
   526  			}
   527  			d := string(data)
   528  			expected := sysmetrics.ExpectedReportItem
   529  			if tc.sendOnlyOptOutData {
   530  				expected = sysmetrics.OptOutJSON
   531  			}
   532  			if !strings.Contains(d, expected) {
   533  				t.Errorf("we expected to find %s in report file, got: %s", expected, d)
   534  			}
   535  		})
   536  	}
   537  }
   538  
   539  func TestCollectAndSendOnUpgrade(t *testing.T) {
   540  	// we change current path and env variable: not parallelizable tests
   541  	helper.SkipIfShort(t)
   542  
   543  	testCases := []struct {
   544  		name            string
   545  		previousReportP string
   546  
   547  		shouldHitServer bool
   548  		wantOptOut      bool
   549  		wantErr         bool
   550  	}{
   551  		{"with previous report, previous release opt in",
   552  			"testdata/previous_reports/previous_release_optin",
   553  			true, false, false},
   554  		{"with previous report, previous release opt out",
   555  			"testdata/previous_reports/previous_release_optout",
   556  			true, true, false},
   557  	}
   558  	for _, tc := range testCases {
   559  		tc := tc // capture range variable for parallel execution
   560  		t.Run(tc.name, func(t *testing.T) {
   561  			a := helper.Asserter{T: t}
   562  
   563  			out, tearDown := helper.TempDir(t)
   564  			defer tearDown()
   565  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   566  			out = filepath.Join(out, "ubuntu-report")
   567  			// we don't really care where we hit for this API integration test, internal ones test it
   568  			// and we don't really control /etc/os-release version and id.
   569  			// Same for report file
   570  			serverHit := false
   571  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   572  				serverHit = true
   573  			}))
   574  			defer ts.Close()
   575  
   576  			if tc.previousReportP != "" {
   577  				if err := os.MkdirAll(out, 0700); err != nil {
   578  					t.Fatalf("couldn't create report directory: %v", err)
   579  				}
   580  				files, err := ioutil.ReadDir(tc.previousReportP)
   581  				if err != nil {
   582  					t.Fatalf("couldn't list files under %s: %v", tc.previousReportP, err)
   583  				}
   584  				for _, file := range files {
   585  					data, err := ioutil.ReadFile(filepath.Join(tc.previousReportP, file.Name()))
   586  					if err != nil {
   587  						t.Fatalf("couldn't read report file: %v", err)
   588  					}
   589  					if err = ioutil.WriteFile(filepath.Join(out, file.Name()), data, 0644); err != nil {
   590  						t.Fatalf("couldn't write to destination report file in setup: %v", err)
   591  					}
   592  				}
   593  			}
   594  
   595  			err := sysmetrics.CollectAndSendOnUpgrade(false, ts.URL)
   596  
   597  			if err != nil {
   598  				t.Fatal("we didn't expect getting an error, got:", err)
   599  			}
   600  
   601  			a.Equal(serverHit, tc.shouldHitServer)
   602  
   603  			// get highest report path
   604  			reportP := ""
   605  			files, err := ioutil.ReadDir(out)
   606  			if err != nil {
   607  				t.Fatalf("couldn't scan %s: %v", out, err)
   608  			}
   609  			for _, f := range files {
   610  				if f.Name() > reportP {
   611  					reportP = f.Name()
   612  				}
   613  			}
   614  
   615  			gotF, err := os.Open(filepath.Join(out, reportP))
   616  			if err != nil {
   617  				t.Fatal("didn't generate a report file on disk", err)
   618  			}
   619  			got, err := ioutil.ReadAll(gotF)
   620  			if err != nil {
   621  				t.Fatal("couldn't read generated report file", err)
   622  			}
   623  			isOptOut := strings.Contains(string(got), sysmetrics.OptOutJSON)
   624  
   625  			if tc.wantOptOut && !isOptOut {
   626  				t.Errorf("we wanted an opt out as we opted out in previous release but got some data in: %s", got)
   627  			} else if !tc.wantOptOut && isOptOut {
   628  				t.Errorf("we wanted some data which are not opt out information, but got opt out content instead")
   629  			}
   630  		})
   631  	}
   632  }
   633  
   634  func TestSendPendingReport(t *testing.T) {
   635  	// we change current path and env variable: not parallelizable tests
   636  	helper.SkipIfShort(t)
   637  
   638  	testCases := []struct {
   639  		name string
   640  
   641  		shouldHitServer bool
   642  		wantErr         bool
   643  	}{
   644  		{"regular send", true, false},
   645  	}
   646  	for _, tc := range testCases {
   647  		tc := tc // capture range variable for parallel execution
   648  		t.Run(tc.name, func(t *testing.T) {
   649  			a := helper.Asserter{T: t}
   650  
   651  			out, tearDown := helper.TempDir(t)
   652  			defer tearDown()
   653  			defer helper.ChangeEnv("XDG_CACHE_HOME", out)()
   654  			out = filepath.Join(out, "ubuntu-report")
   655  
   656  			pendingReportData, err := ioutil.ReadFile(filepath.Join("testdata", "good", "ubuntu-report", "pending"))
   657  			if err != nil {
   658  				t.Fatalf("couldn't open pending report file: %v", err)
   659  			}
   660  			pendingReportPath := filepath.Join(out, "pending")
   661  			if err := os.MkdirAll(out, 0700); err != nil {
   662  				t.Fatal("couldn't create parent directory of pending report", err)
   663  			}
   664  			if err := ioutil.WriteFile(pendingReportPath, pendingReportData, 0644); err != nil {
   665  				t.Fatalf("couldn't copy pending report file to cache directory: %v", err)
   666  			}
   667  
   668  			// we don't really care where we hit for this API integration test, internal ones test it
   669  			// and we don't really control /etc/os-release version and id.
   670  			// Same for report file
   671  			serverHit := false
   672  			ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   673  				serverHit = true
   674  			}))
   675  			defer ts.Close()
   676  
   677  			err = sysmetrics.SendPendingReport(ts.URL)
   678  
   679  			a.CheckWantedErr(err, tc.wantErr)
   680  			a.Equal(serverHit, tc.shouldHitServer)
   681  
   682  			if _, pendingReportErr := os.Stat(pendingReportPath); os.IsExist(pendingReportErr) {
   683  				t.Errorf("we expected the pending report to be removed and it wasn't")
   684  			}
   685  
   686  			p := filepath.Join(out, helper.FindInDirectory(t, "", out))
   687  			got, err := ioutil.ReadFile(p)
   688  			if err != nil {
   689  				t.Fatalf("couldn't open report file %s", out)
   690  			}
   691  			a.Equal(got, pendingReportData)
   692  		})
   693  	}
   694  }