From 6df5ef36b903f4a58bda29ce2e8bce457360b8cd Mon Sep 17 00:00:00 2001 From: Peng Yin Date: Fri, 17 Nov 2017 00:49:40 +0000 Subject: [PATCH] windows: adding functional test for cpu percent --- .../telemetry-windows/task-definition.json | 11 ++++---- .../tests/functionaltests_unix_test.go | 12 ++++----- .../tests/functionaltests_windows_test.go | 25 +++++++++++++------ agent/functional_tests/util/utils.go | 16 ++++++------ misc/windows-cpupercent/build.ps1 | 14 +++++++++++ misc/windows-cpupercent/main.go | 24 ++++++++++++++++++ misc/windows-cpupercent/windows.dockerfile | 18 +++++++++++++ scripts/run-functional-tests.ps1 | 1 + 8 files changed, 94 insertions(+), 27 deletions(-) create mode 100644 misc/windows-cpupercent/build.ps1 create mode 100644 misc/windows-cpupercent/main.go create mode 100644 misc/windows-cpupercent/windows.dockerfile diff --git a/agent/functional_tests/testdata/taskdefinitions/telemetry-windows/task-definition.json b/agent/functional_tests/testdata/taskdefinitions/telemetry-windows/task-definition.json index ca21837602c..b50de930cc9 100644 --- a/agent/functional_tests/testdata/taskdefinitions/telemetry-windows/task-definition.json +++ b/agent/functional_tests/testdata/taskdefinitions/telemetry-windows/task-definition.json @@ -1,10 +1,9 @@ { - "family": "ecsftest-telemetry-windows", + "family": "ecsftest-windows-telemetry", "containerDefinitions": [{ - "image": "microsoft/iis:latest", - "name": "http_server", - "cpu": 100, - "memory": 500, - "command": ["powershell", "-c", "New-Item -Path C:\\inetpub\\wwwroot\\index.html -Type file -Value ' Amazon ECS Sample App

Amazon ECS Sample App

Congratulations!

Your application is now running on a container in Amazon ECS.

'; C:\\ServiceMonitor.exe w3svc"] + "image": "amazon/amazon-ecs-windows-cpupercent-test:make", + "name": "windows-cpu-percent", + "cpu": $$$$CPUSHARE$$$$, + "memory": 500 }] } diff --git a/agent/functional_tests/tests/functionaltests_unix_test.go b/agent/functional_tests/tests/functionaltests_unix_test.go index 302a517f462..1b56ee3f9b9 100644 --- a/agent/functional_tests/tests/functionaltests_unix_test.go +++ b/agent/functional_tests/tests/functionaltests_unix_test.go @@ -383,11 +383,11 @@ func TestTelemetry(t *testing.T) { time.Sleep(waitMetricsInCloudwatchDuration) cwclient := cloudwatch.New(session.New(), aws.NewConfig().WithRegion(*ECS.Config.Region)) - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Before task running, verify metrics for CPU utilization failed") params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Before task running, verify metrics for memory utilization failed") testTask, err := agent.StartTask(t, "telemetry") @@ -400,11 +400,11 @@ func TestTelemetry(t *testing.T) { params.EndTime = aws.Time(RoundTimeUp(time.Now(), time.Minute).UTC()) params.StartTime = aws.Time((*params.EndTime).Add(-waitMetricsInCloudwatchDuration).UTC()) params.MetricName = aws.String("CPUUtilization") - err = VerifyMetrics(cwclient, params, false) + err, _ = VerifyMetrics(cwclient, params, false) assert.NoError(t, err, "Task is running, verify metrics for CPU utilization failed") params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, false) + err, _ = VerifyMetrics(cwclient, params, false) assert.NoError(t, err, "Task is running, verify metrics for memory utilization failed") err = testTask.Stop() @@ -417,11 +417,11 @@ func TestTelemetry(t *testing.T) { params.EndTime = aws.Time(RoundTimeUp(time.Now(), time.Minute).UTC()) params.StartTime = aws.Time((*params.EndTime).Add(-waitMetricsInCloudwatchDuration).UTC()) params.MetricName = aws.String("CPUUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Task stopped: verify metrics for CPU utilization failed") params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Task stopped, verify metrics for memory utilization failed") } diff --git a/agent/functional_tests/tests/functionaltests_windows_test.go b/agent/functional_tests/tests/functionaltests_windows_test.go index c36f34d3a2d..34936b28be6 100644 --- a/agent/functional_tests/tests/functionaltests_windows_test.go +++ b/agent/functional_tests/tests/functionaltests_windows_test.go @@ -18,6 +18,8 @@ package functional_tests import ( "fmt" "os" + "runtime" + "strconv" "strings" "testing" "time" @@ -266,14 +268,20 @@ func TestTelemetry(t *testing.T) { time.Sleep(waitMetricsInCloudwatchDuration) cwclient := cloudwatch.New(session.New(), aws.NewConfig().WithRegion(*ECS.Config.Region)) - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Before task running, verify metrics for CPU utilization failed") params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Before task running, verify metrics for memory utilization failed") - testTask, err := agent.StartTask(t, "telemetry-windows") + cpuNum := runtime.NumCPU() + + tdOverrides := make(map[string]string) + // Set the container cpu percentage 25% + tdOverrides["$$$$CPUSHARE$$$$"] = strconv.Itoa(cpuNum * 1024 / 4) + + testTask, err := agent.StartTaskWithTaskDefinitionOverrides(t, "telemetry-windows", tdOverrides) require.NoError(t, err, "Failed to start telemetry task") // Wait for the task to run and the agent to send back metrics err = testTask.WaitRunning(waitTaskStateChangeDuration) @@ -283,11 +291,14 @@ func TestTelemetry(t *testing.T) { params.EndTime = aws.Time(RoundTimeUp(time.Now(), time.Minute).UTC()) params.StartTime = aws.Time((*params.EndTime).Add(-waitMetricsInCloudwatchDuration).UTC()) params.MetricName = aws.String("CPUUtilization") - err = VerifyMetrics(cwclient, params, false) + err, metrics := VerifyMetrics(cwclient, params, false) assert.NoError(t, err, "Task is running, verify metrics for CPU utilization failed") + // Also verify the cpu usage is around 25% + assert.True(t, *metrics.Average < 0.3) + assert.True(t, *metrics.Average > 0.2) params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, false) + err, _ = VerifyMetrics(cwclient, params, false) assert.NoError(t, err, "Task is running, verify metrics for memory utilization failed") err = testTask.Stop() @@ -300,10 +311,10 @@ func TestTelemetry(t *testing.T) { params.EndTime = aws.Time(RoundTimeUp(time.Now(), time.Minute).UTC()) params.StartTime = aws.Time((*params.EndTime).Add(-waitMetricsInCloudwatchDuration).UTC()) params.MetricName = aws.String("CPUUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Task stopped: verify metrics for CPU utilization failed") params.MetricName = aws.String("MemoryUtilization") - err = VerifyMetrics(cwclient, params, true) + err, _ = VerifyMetrics(cwclient, params, true) assert.NoError(t, err, "Task stopped, verify metrics for memory utilization failed") } diff --git a/agent/functional_tests/util/utils.go b/agent/functional_tests/util/utils.go index 90867537da8..98fa983f02b 100644 --- a/agent/functional_tests/util/utils.go +++ b/agent/functional_tests/util/utils.go @@ -266,36 +266,36 @@ func DeleteCluster(t *testing.T, clusterName string) { // VerifyMetrics whether the response is as expected // the expected value can be 0 or positive -func VerifyMetrics(cwclient *cloudwatch.CloudWatch, params *cloudwatch.GetMetricStatisticsInput, idleCluster bool) error { +func VerifyMetrics(cwclient *cloudwatch.CloudWatch, params *cloudwatch.GetMetricStatisticsInput, idleCluster bool) (error, *cloudwatch.Datapoint) { resp, err := cwclient.GetMetricStatistics(params) if err != nil { - return fmt.Errorf("Error getting metrics of cluster: %v", err) + return fmt.Errorf("Error getting metrics of cluster: %v", err), nil } if resp == nil || resp.Datapoints == nil { - return fmt.Errorf("Cloudwatch get metrics failed, returned null") + return fmt.Errorf("Cloudwatch get metrics failed, returned null"), nil } metricsCount := len(resp.Datapoints) if metricsCount == 0 { - return fmt.Errorf("No datapoints returned") + return fmt.Errorf("No datapoints returned"), nil } datapoint := resp.Datapoints[metricsCount-1] // Samplecount is always expected to be "1" for cluster metrics if *datapoint.SampleCount != 1.0 { - return fmt.Errorf("Incorrect SampleCount %f, expected 1", *datapoint.SampleCount) + return fmt.Errorf("Incorrect SampleCount %f, expected 1", *datapoint.SampleCount), nil } if idleCluster { if *datapoint.Average != 0.0 { - return fmt.Errorf("non-zero utilization for idle cluster") + return fmt.Errorf("non-zero utilization for idle cluster"), nil } } else { if *datapoint.Average == 0.0 { - return fmt.Errorf("utilization is zero for non-idle cluster") + return fmt.Errorf("utilization is zero for non-idle cluster"), nil } } - return nil + return nil, datapoint } // ResolveTaskDockerID determines the Docker ID for a container within a given diff --git a/misc/windows-cpupercent/build.ps1 b/misc/windows-cpupercent/build.ps1 new file mode 100644 index 00000000000..529f3dcef95 --- /dev/null +++ b/misc/windows-cpupercent/build.ps1 @@ -0,0 +1,14 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. + +docker build -t "amazon/amazon-ecs-windows-cpupercent-test:make" -f "${PSScriptRoot}/windows.dockerfile" ${PSScriptRoot} diff --git a/misc/windows-cpupercent/main.go b/misc/windows-cpupercent/main.go new file mode 100644 index 00000000000..acc3450c44b --- /dev/null +++ b/misc/windows-cpupercent/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "crypto/md5" + "flag" + "fmt" +) + +func main() { + concurrency := flag.Int("concurrency", 1, "amount of concurrency") + flag.Parse() + neverdie := make(chan struct{}) + + fmt.Printf("Hogging CPU with concurrency %d\n", *concurrency) + for i := 0; i < *concurrency; i++ { + go func() { + md5hash := md5.New() + for { + md5hash.Write([]byte{0}) + } + }() + } + <-neverdie +} diff --git a/misc/windows-cpupercent/windows.dockerfile b/misc/windows-cpupercent/windows.dockerfile new file mode 100644 index 00000000000..f6eb0194970 --- /dev/null +++ b/misc/windows-cpupercent/windows.dockerfile @@ -0,0 +1,18 @@ +# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). You may +# not use this file except in compliance with the License. A copy of the +# License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file is distributed +# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +# express or implied. See the License for the specific language governing +# permissions and limitations under the License. +FROM golang:nanoserver + +WORKDIR /gopath +COPY main.go . + +CMD ["go", "run", "main.go", "-concurrency", "1000"] diff --git a/scripts/run-functional-tests.ps1 b/scripts/run-functional-tests.ps1 index 7b78e046d09..20aea6af795 100644 --- a/scripts/run-functional-tests.ps1 +++ b/scripts/run-functional-tests.ps1 @@ -13,6 +13,7 @@ Invoke-Expression "${PSScriptRoot}\..\misc\windows-iam\Setup_Iam.ps1" Invoke-Expression "${PSScriptRoot}\..\misc\windows-listen80\Setup_Listen80.ps1" +Invoke-Expression "${PSScriptRoot}\..\misc\windows-cpupercent\build.ps1" # Run the tests $cwd = (pwd).Path