@@ -951,19 +951,17 @@ func TestAgent_StartupScript(t *testing.T) {
951
951
func TestAgent_Metadata (t * testing.T ) {
952
952
t .Parallel ()
953
953
954
+ echoHello := "echo 'hello'"
955
+
954
956
t .Run ("Once" , func (t * testing.T ) {
955
957
t .Parallel ()
956
- script := "echo -n hello"
957
- if runtime .GOOS == "windows" {
958
- script = "powershell " + script
959
- }
960
958
//nolint:dogsled
961
959
_ , client , _ , _ , _ := setupAgent (t , agentsdk.Manifest {
962
960
Metadata : []codersdk.WorkspaceAgentMetadataDescription {
963
961
{
964
962
Key : "greeting" ,
965
963
Interval : 0 ,
966
- Script : script ,
964
+ Script : echoHello ,
967
965
},
968
966
},
969
967
}, 0 )
@@ -986,78 +984,111 @@ func TestAgent_Metadata(t *testing.T) {
986
984
})
987
985
988
986
t .Run ("Many" , func (t * testing.T ) {
989
- if runtime .GOOS == "windows" {
990
- // Shell scripting in Windows is a pain, and we have already tested
991
- // that the OS logic works in the simpler "Once" test above.
992
- t .Skip ()
993
- }
994
987
t .Parallel ()
995
-
996
- dir := t .TempDir ()
997
-
998
- const reportInterval = 2
999
- const intervalUnit = 100 * time .Millisecond
1000
- var (
1001
- greetingPath = filepath .Join (dir , "greeting" )
1002
- script = "echo hello | tee -a " + greetingPath
1003
- )
988
+ //nolint:dogsled
1004
989
_ , client , _ , _ , _ := setupAgent (t , agentsdk.Manifest {
1005
990
Metadata : []codersdk.WorkspaceAgentMetadataDescription {
1006
991
{
1007
992
Key : "greeting" ,
1008
- Interval : reportInterval ,
1009
- Script : script ,
1010
- },
1011
- {
1012
- Key : "bad" ,
1013
- Interval : reportInterval ,
1014
- Script : "exit 1" ,
993
+ Interval : 1 ,
994
+ Timeout : 100 ,
995
+ Script : echoHello ,
1015
996
},
1016
997
},
1017
998
}, 0 )
1018
999
1000
+ var gotMd map [string ]agentsdk.PostMetadataRequest
1019
1001
require .Eventually (t , func () bool {
1020
- return len (client .getMetadata ()) == 2
1002
+ gotMd = client .getMetadata ()
1003
+ return len (gotMd ) == 1
1021
1004
}, testutil .WaitShort , testutil .IntervalMedium )
1022
1005
1023
- for start := time .Now (); time .Since (start ) < testutil .WaitMedium ; time .Sleep (testutil .IntervalMedium ) {
1024
- md := client .getMetadata ()
1025
- if len (md ) != 2 {
1026
- panic ("unexpected number of metadata entries" )
1027
- }
1006
+ collectedAt1 := gotMd ["greeting" ].CollectedAt
1007
+ if ! assert .Equal (t , "hello" , strings .TrimSpace (gotMd ["greeting" ].Value )) {
1008
+ t .Errorf ("got: %+v" , gotMd )
1009
+ }
1028
1010
1029
- require .Equal (t , "hello\n " , md ["greeting" ].Value )
1030
- require .Equal (t , "exit status 1" , md ["bad" ].Error )
1011
+ if ! assert .Eventually (t , func () bool {
1012
+ gotMd = client .getMetadata ()
1013
+ return gotMd ["greeting" ].CollectedAt .After (collectedAt1 )
1014
+ }, testutil .WaitShort , testutil .IntervalMedium ) {
1015
+ t .Fatalf ("expected metadata to be collected again" )
1016
+ }
1017
+ })
1018
+ }
1031
1019
1032
- greetingByt , err := os .ReadFile (greetingPath )
1033
- require .NoError (t , err )
1020
+ func TestAgentMetadata_Timing (t * testing.T ) {
1021
+ if runtime .GOOS == "windows" {
1022
+ // Shell scripting in Windows is a pain, and we have already tested
1023
+ // that the OS logic works in the simpler tests.
1024
+ t .Skip ()
1025
+ }
1026
+ testutil .SkipIfNotTiming (t )
1027
+ t .Parallel ()
1034
1028
1035
- var (
1036
- numGreetings = bytes .Count (greetingByt , []byte ("hello" ))
1037
- idealNumGreetings = time .Since (start ) / (reportInterval * intervalUnit )
1038
- // We allow a 50% error margin because the report loop may backlog
1039
- // in CI and other toasters. In production, there is no hard
1040
- // guarantee on timing either, and the frontend gives similar
1041
- // wiggle room to the staleness of the value.
1042
- upperBound = int (idealNumGreetings ) + 1
1043
- lowerBound = (int (idealNumGreetings ) / 2 )
1044
- )
1045
-
1046
- if idealNumGreetings < 50 {
1047
- // There is an insufficient sample size.
1048
- continue
1049
- }
1029
+ dir := t .TempDir ()
1050
1030
1051
- t .Logf ("numGreetings: %d, idealNumGreetings: %d" , numGreetings , idealNumGreetings )
1052
- // The report loop may slow down on load, but it should never, ever
1053
- // speed up.
1054
- if numGreetings > upperBound {
1055
- t .Fatalf ("too many greetings: %d > %d in %v" , numGreetings , upperBound , time .Since (start ))
1056
- } else if numGreetings < lowerBound {
1057
- t .Fatalf ("too few greetings: %d < %d" , numGreetings , lowerBound )
1058
- }
1031
+ const reportInterval = 2
1032
+ const intervalUnit = 100 * time .Millisecond
1033
+ var (
1034
+ greetingPath = filepath .Join (dir , "greeting" )
1035
+ script = "echo hello | tee -a " + greetingPath
1036
+ )
1037
+ //nolint:dogsled
1038
+ _ , client , _ , _ , _ := setupAgent (t , agentsdk.Manifest {
1039
+ Metadata : []codersdk.WorkspaceAgentMetadataDescription {
1040
+ {
1041
+ Key : "greeting" ,
1042
+ Interval : reportInterval ,
1043
+ Script : script ,
1044
+ },
1045
+ {
1046
+ Key : "bad" ,
1047
+ Interval : reportInterval ,
1048
+ Script : "exit 1" ,
1049
+ },
1050
+ },
1051
+ }, 0 )
1052
+
1053
+ require .Eventually (t , func () bool {
1054
+ return len (client .getMetadata ()) == 2
1055
+ }, testutil .WaitShort , testutil .IntervalMedium )
1056
+
1057
+ for start := time .Now (); time .Since (start ) < testutil .WaitMedium ; time .Sleep (testutil .IntervalMedium ) {
1058
+ md := client .getMetadata ()
1059
+ require .Len (t , md , 2 , "got: %+v" , md )
1060
+
1061
+ require .Equal (t , "hello\n " , md ["greeting" ].Value )
1062
+ require .Equal (t , "run cmd: exit status 1" , md ["bad" ].Error )
1063
+
1064
+ greetingByt , err := os .ReadFile (greetingPath )
1065
+ require .NoError (t , err )
1066
+
1067
+ var (
1068
+ numGreetings = bytes .Count (greetingByt , []byte ("hello" ))
1069
+ idealNumGreetings = time .Since (start ) / (reportInterval * intervalUnit )
1070
+ // We allow a 50% error margin because the report loop may backlog
1071
+ // in CI and other toasters. In production, there is no hard
1072
+ // guarantee on timing either, and the frontend gives similar
1073
+ // wiggle room to the staleness of the value.
1074
+ upperBound = int (idealNumGreetings ) + 1
1075
+ lowerBound = (int (idealNumGreetings ) / 2 )
1076
+ )
1077
+
1078
+ if idealNumGreetings < 50 {
1079
+ // There is an insufficient sample size.
1080
+ continue
1059
1081
}
1060
- })
1082
+
1083
+ t .Logf ("numGreetings: %d, idealNumGreetings: %d" , numGreetings , idealNumGreetings )
1084
+ // The report loop may slow down on load, but it should never, ever
1085
+ // speed up.
1086
+ if numGreetings > upperBound {
1087
+ t .Fatalf ("too many greetings: %d > %d in %v" , numGreetings , upperBound , time .Since (start ))
1088
+ } else if numGreetings < lowerBound {
1089
+ t .Fatalf ("too few greetings: %d < %d" , numGreetings , lowerBound )
1090
+ }
1091
+ }
1061
1092
}
1062
1093
1063
1094
func TestAgent_Lifecycle (t * testing.T ) {
0 commit comments