@@ -39,6 +39,7 @@ import (
39
39
"tailscale.com/types/key"
40
40
41
41
"cdr.dev/slog/sloggers/slogtest"
42
+ "github.com/coder/coder/v2/buildinfo"
42
43
"github.com/coder/coder/v2/cli"
43
44
"github.com/coder/coder/v2/cli/clitest"
44
45
"github.com/coder/coder/v2/cli/config"
@@ -947,36 +948,40 @@ func TestServer(t *testing.T) {
947
948
t .Run ("Telemetry" ,func (t * testing.T ) {
948
949
t .Parallel ()
949
950
950
- deployment := make (chan struct {},64 )
951
- snapshot := make (chan * telemetry.Snapshot ,64 )
952
- r := chi .NewRouter ()
953
- r .Post ("/deployment" ,func (w http.ResponseWriter ,r * http.Request ) {
954
- w .WriteHeader (http .StatusAccepted )
955
- deployment <- struct {}{}
956
- })
957
- r .Post ("/snapshot" ,func (w http.ResponseWriter ,r * http.Request ) {
958
- w .WriteHeader (http .StatusAccepted )
959
- ss := & telemetry.Snapshot {}
960
- err := json .NewDecoder (r .Body ).Decode (ss )
961
- require .NoError (t ,err )
962
- snapshot <- ss
963
- })
964
- server := httptest .NewServer (r )
965
- defer server .Close ()
951
+ telemetryServerURL ,deployment ,snapshot := mockTelemetryServer (t )
966
952
967
- inv ,_ := clitest .New (t ,
953
+ inv ,cfg := clitest .New (t ,
968
954
"server" ,
969
955
"--in-memory" ,
970
956
"--http-address" ,":0" ,
971
957
"--access-url" ,"http://example.com" ,
972
958
"--telemetry" ,
973
- "--telemetry-url" ,server . URL ,
959
+ "--telemetry-url" ,telemetryServerURL . String () ,
974
960
"--cache-dir" ,t .TempDir (),
975
961
)
976
962
clitest .Start (t ,inv )
977
963
978
964
<- deployment
979
965
<- snapshot
966
+
967
+ accessURL := waitAccessURL (t ,cfg )
968
+
969
+ ctx := testutil .Context (t ,testutil .WaitMedium )
970
+ client := codersdk .New (accessURL )
971
+ body ,err := client .Request (ctx ,http .MethodGet ,"/" ,nil )
972
+ require .NoError (t ,err )
973
+ require .NoError (t ,body .Body .Close ())
974
+
975
+ require .Eventually (t ,func ()bool {
976
+ snap := <- snapshot
977
+ htmlFirstServedFound := false
978
+ for _ ,item := range snap .TelemetryItems {
979
+ if item .Key == string (telemetry .TelemetryItemKeyHTMLFirstServedAt ) {
980
+ htmlFirstServedFound = true
981
+ }
982
+ }
983
+ return htmlFirstServedFound
984
+ },testutil .WaitMedium ,testutil .IntervalFast ,"no html_first_served telemetry item" )
980
985
})
981
986
t .Run ("Prometheus" ,func (t * testing.T ) {
982
987
t .Parallel ()
@@ -1990,3 +1995,148 @@ func TestServer_DisabledDERP(t *testing.T) {
1990
1995
err = c .Connect (ctx )
1991
1996
require .Error (t ,err )
1992
1997
}
1998
+
1999
+ type runServerOpts struct {
2000
+ waitForSnapshot bool
2001
+ telemetryDisabled bool
2002
+ waitForTelemetryDisabledCheck bool
2003
+ }
2004
+
2005
+ func TestServer_TelemetryDisabled_FinalReport (t * testing.T ) {
2006
+ t .Parallel ()
2007
+
2008
+ if ! dbtestutil .WillUsePostgres () {
2009
+ t .Skip ("this test requires postgres" )
2010
+ }
2011
+
2012
+ telemetryServerURL ,deployment ,snapshot := mockTelemetryServer (t )
2013
+ dbConnURL ,err := dbtestutil .Open (t )
2014
+ require .NoError (t ,err )
2015
+
2016
+ cacheDir := t .TempDir ()
2017
+ runServer := func (t * testing.T ,opts runServerOpts ) (chan error , context.CancelFunc ) {
2018
+ ctx ,cancelFunc := context .WithCancel (context .Background ())
2019
+ inv ,_ := clitest .New (t ,
2020
+ "server" ,
2021
+ "--postgres-url" ,dbConnURL ,
2022
+ "--http-address" ,":0" ,
2023
+ "--access-url" ,"http://example.com" ,
2024
+ "--telemetry=" + strconv .FormatBool (! opts .telemetryDisabled ),
2025
+ "--telemetry-url" ,telemetryServerURL .String (),
2026
+ "--cache-dir" ,cacheDir ,
2027
+ "--log-filter" ,".*" ,
2028
+ )
2029
+ finished := make (chan bool ,2 )
2030
+ errChan := make (chan error ,1 )
2031
+ pty := ptytest .New (t ).Attach (inv )
2032
+ go func () {
2033
+ errChan <- inv .WithContext (ctx ).Run ()
2034
+ finished <- true
2035
+ }()
2036
+ go func () {
2037
+ defer func () {
2038
+ finished <- true
2039
+ }()
2040
+ if opts .waitForSnapshot {
2041
+ pty .ExpectMatchContext (testutil .Context (t ,testutil .WaitLong ),"submitted snapshot" )
2042
+ }
2043
+ if opts .waitForTelemetryDisabledCheck {
2044
+ pty .ExpectMatchContext (testutil .Context (t ,testutil .WaitLong ),"finished telemetry status check" )
2045
+ }
2046
+ }()
2047
+ <- finished
2048
+ return errChan ,cancelFunc
2049
+ }
2050
+ waitForShutdown := func (t * testing.T ,errChan chan error )error {
2051
+ t .Helper ()
2052
+ select {
2053
+ case err := <- errChan :
2054
+ return err
2055
+ case <- time .After (testutil .WaitMedium ):
2056
+ t .Fatalf ("timed out waiting for server to shutdown" )
2057
+ }
2058
+ return nil
2059
+ }
2060
+
2061
+ errChan ,cancelFunc := runServer (t ,runServerOpts {telemetryDisabled :true ,waitForTelemetryDisabledCheck :true })
2062
+ cancelFunc ()
2063
+ require .NoError (t ,waitForShutdown (t ,errChan ))
2064
+
2065
+ // Since telemetry was disabled, we expect no deployments or snapshots.
2066
+ require .Empty (t ,deployment )
2067
+ require .Empty (t ,snapshot )
2068
+
2069
+ errChan ,cancelFunc = runServer (t ,runServerOpts {waitForSnapshot :true })
2070
+ cancelFunc ()
2071
+ require .NoError (t ,waitForShutdown (t ,errChan ))
2072
+ // we expect to see a deployment and a snapshot twice:
2073
+ // 1. the first pair is sent when the server starts
2074
+ // 2. the second pair is sent when the server shuts down
2075
+ for i := 0 ;i < 2 ;i ++ {
2076
+ select {
2077
+ case <- snapshot :
2078
+ case <- time .After (testutil .WaitShort / 2 ):
2079
+ t .Fatalf ("timed out waiting for snapshot" )
2080
+ }
2081
+ select {
2082
+ case <- deployment :
2083
+ case <- time .After (testutil .WaitShort / 2 ):
2084
+ t .Fatalf ("timed out waiting for deployment" )
2085
+ }
2086
+ }
2087
+
2088
+ errChan ,cancelFunc = runServer (t ,runServerOpts {telemetryDisabled :true ,waitForTelemetryDisabledCheck :true })
2089
+ cancelFunc ()
2090
+ require .NoError (t ,waitForShutdown (t ,errChan ))
2091
+
2092
+ // Since telemetry is disabled, we expect no deployment. We expect a snapshot
2093
+ // with the telemetry disabled item.
2094
+ require .Empty (t ,deployment )
2095
+ select {
2096
+ case ss := <- snapshot :
2097
+ require .Len (t ,ss .TelemetryItems ,1 )
2098
+ require .Equal (t ,string (telemetry .TelemetryItemKeyTelemetryEnabled ),ss .TelemetryItems [0 ].Key )
2099
+ require .Equal (t ,"false" ,ss .TelemetryItems [0 ].Value )
2100
+ case <- time .After (testutil .WaitShort / 2 ):
2101
+ t .Fatalf ("timed out waiting for snapshot" )
2102
+ }
2103
+
2104
+ errChan ,cancelFunc = runServer (t ,runServerOpts {telemetryDisabled :true ,waitForTelemetryDisabledCheck :true })
2105
+ cancelFunc ()
2106
+ require .NoError (t ,waitForShutdown (t ,errChan ))
2107
+ // Since telemetry is disabled and we've already sent a snapshot, we expect no
2108
+ // new deployments or snapshots.
2109
+ require .Empty (t ,deployment )
2110
+ require .Empty (t ,snapshot )
2111
+ }
2112
+
2113
+ func mockTelemetryServer (t * testing.T ) (* url.URL ,chan * telemetry.Deployment ,chan * telemetry.Snapshot ) {
2114
+ t .Helper ()
2115
+ deployment := make (chan * telemetry.Deployment ,64 )
2116
+ snapshot := make (chan * telemetry.Snapshot ,64 )
2117
+ r := chi .NewRouter ()
2118
+ r .Post ("/deployment" ,func (w http.ResponseWriter ,r * http.Request ) {
2119
+ require .Equal (t ,buildinfo .Version (),r .Header .Get (telemetry .VersionHeader ))
2120
+ dd := & telemetry.Deployment {}
2121
+ err := json .NewDecoder (r .Body ).Decode (dd )
2122
+ require .NoError (t ,err )
2123
+ deployment <- dd
2124
+ // Ensure the header is sent only after deployment is sent
2125
+ w .WriteHeader (http .StatusAccepted )
2126
+ })
2127
+ r .Post ("/snapshot" ,func (w http.ResponseWriter ,r * http.Request ) {
2128
+ require .Equal (t ,buildinfo .Version (),r .Header .Get (telemetry .VersionHeader ))
2129
+ ss := & telemetry.Snapshot {}
2130
+ err := json .NewDecoder (r .Body ).Decode (ss )
2131
+ require .NoError (t ,err )
2132
+ snapshot <- ss
2133
+ // Ensure the header is sent only after snapshot is sent
2134
+ w .WriteHeader (http .StatusAccepted )
2135
+ })
2136
+ server := httptest .NewServer (r )
2137
+ t .Cleanup (server .Close )
2138
+ serverURL ,err := url .Parse (server .URL )
2139
+ require .NoError (t ,err )
2140
+
2141
+ return serverURL ,deployment ,snapshot
2142
+ }