github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/client/internal/monitoring/resource_usage_fetcher_test.go (about)

     1  // Copyright 2017 Google Inc.
     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  //     https://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  
    15  package monitoring
    16  
    17  import (
    18  	"fmt"
    19  	"os/exec"
    20  	"runtime"
    21  	"testing"
    22  	"time"
    23  
    24  	log "github.com/golang/glog"
    25  )
    26  
    27  func checkFloat64(name string, value, min, max float64) error {
    28  	if value < min || value > max {
    29  		return fmt.Errorf("Expected %s to be between %v and %v, got %v", name, min, max, value)
    30  	}
    31  	return nil
    32  }
    33  
    34  func checkInt64(name string, value, min, max int64) error {
    35  	if value < min || value > max {
    36  		return fmt.Errorf("Expected %s to be between %d and %d, got %d", name, min, max, value)
    37  	}
    38  	return nil
    39  }
    40  
    41  func TestResourceUsageFromFinishedCmd(t *testing.T) {
    42  	ruf := ResourceUsageFetcher{}
    43  	// Generate some system (os.listdir) and user (everything else) execution
    44  	// time, consume some memory...
    45  	cmd := exec.Command("python", "-c", `
    46  import os
    47  import time
    48  
    49  s = ""
    50  for i in range(5000):
    51    s += str(i)
    52  
    53  t0 = time.time()
    54  while time.time() - t0 < 1.:
    55    os.listdir(".")
    56  	`)
    57  	start := time.Now()
    58  	if err := cmd.Run(); err != nil {
    59  		t.Fatalf("Unexpected error from Run(): %v", err)
    60  	}
    61  	runTime := time.Since(start)
    62  	ru := ruf.ResourceUsageFromFinishedCmd(cmd)
    63  
    64  	log.Infof("got resource usage: %#v", ru)
    65  
    66  	// Can CPU time be > observed wall-time if multiple cores are involved?
    67  	if err := checkFloat64("UserCPUMillis", ru.UserCPUMillis, 0.0, runTime.Seconds()*1000.0); err != nil {
    68  		t.Error(err)
    69  	}
    70  	if err := checkFloat64("SystemCPUMillis", ru.SystemCPUMillis, 0.0, runTime.Seconds()*1000.0); err != nil {
    71  		t.Error(err)
    72  	}
    73  
    74  	if ru.Timestamp.Before(start) {
    75  		t.Errorf("Expected timestamp to be at least %v, but it was %v", start, ru.Timestamp)
    76  	}
    77  }
    78  
    79  func TestResourceUsageForPID(t *testing.T) {
    80  	ruf := ResourceUsageFetcher{}
    81  	log.Infof("Testing resource usage on [%s, %s]", runtime.GOARCH, runtime.GOOS)
    82  	// Generate some system (os.listdir) and user (everything else) execution
    83  	// time, consume some memory...
    84  	cmd := exec.Command("python", "-c", `
    85  import os
    86  import time
    87  
    88  s = ""
    89  for i in range(5000):
    90    s += str(i)
    91  
    92  t0 = time.time()
    93  while time.time() - t0 < 60.:
    94    os.listdir(".")
    95  	`)
    96  	start := time.Now()
    97  	if err := cmd.Start(); err != nil {
    98  		t.Fatalf("Unexpected error from Run(): %v", err)
    99  	}
   100  	defer func() {
   101  		if err := cmd.Process.Kill(); err != nil {
   102  			t.Errorf("Error killing cmd: %v", err)
   103  		}
   104  		if err := cmd.Wait(); err != nil {
   105  			log.Errorf("Error waiting for cmd: %v", err)
   106  		}
   107  	}()
   108  	time.Sleep(3 * time.Second)
   109  	runTime := time.Since(start)
   110  	ru, err := ruf.ResourceUsageForPID(cmd.Process.Pid)
   111  	if err != nil {
   112  		t.Fatalf("Error getting ResourceUsageForPid: %v", err)
   113  	}
   114  	log.Infof("got resource usage: %#v", ru)
   115  
   116  	// Can CPU time be > observed wall-time if multiple cores are involved?
   117  	if err := checkFloat64("UserCPUMillis", ru.UserCPUMillis, 0.0, runTime.Seconds()*1000.0); err != nil {
   118  		t.Error(err)
   119  	}
   120  	if err := checkFloat64("SystemCPUMillis", ru.SystemCPUMillis, 0.0, runTime.Seconds()*1000.0); err != nil {
   121  		t.Error(err)
   122  	}
   123  
   124  	if ru.Timestamp.Before(start) {
   125  		t.Errorf("Expected timestamp to be at least %v, but it was %v", start, ru.Timestamp)
   126  	}
   127  	if err := checkInt64("resident memory", ru.ResidentMemory, 128*1024, 100*1024*1024); err != nil {
   128  		t.Error(err)
   129  	}
   130  
   131  	if runtime.GOOS == "linux" {
   132  		if ru.NumFDs == 0 {
   133  			t.Errorf("Expected NumFDs to be non-0.")
   134  		}
   135  	} else {
   136  		if ru.NumFDs != 0 {
   137  			t.Errorf("Expected NumFDs to always be 0 on non-Linux systems.")
   138  		}
   139  	}
   140  
   141  	debugStatus, err := ruf.DebugStatusForPID(cmd.Process.Pid)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	if debugStatus == "" {
   146  		t.Error("Expected debug status to be non-empty.")
   147  	}
   148  }