If I have the PID of a process, is os.FindProcess enough to test for the existing of the process? I mean if it returns err can I assume that it's terminated (or killed)?
Edit:
I've just wrote a wrapper function around kill -s 0 (old-style bash process testing). This works without any problem, but I'm still happy if there is other solutions (done with go libraries) to this problem.:
func checkPid(pid int) bool {
out, err := exec.Command("kill", "-s", "0", strconv.Itoa(pid)).CombinedOutput()
if err != nil {
log.Println(err)
}
if string(out) == "" {
return true // pid exist
}
return false
}
Here is the traditional unix way to see if a process is alive - send it a signal of 0 (like you did with your bash example).
From kill(2):
If sig is 0, then no signal is sent, but error checking is still per‐
formed; this can be used to check for the existence of a process ID or
process group ID.
And translated into Go
package main
import (
"fmt"
"log"
"os"
"strconv"
"syscall"
)
func main() {
for _, p := range os.Args[1:] {
pid, err := strconv.ParseInt(p, 10, 64)
if err != nil {
log.Fatal(err)
}
process, err := os.FindProcess(int(pid))
if err != nil {
fmt.Printf("Failed to find process: %s\n", err)
} else {
err := process.Signal(syscall.Signal(0))
fmt.Printf("process.Signal on pid %d returned: %v\n", pid, err)
}
}
}
When you run it you get this, showing that process 123 is dead, process 1 is alive but not owned by you and process 12606 is alive and owned by you.
$ ./kill 1 $$ 123
process.Signal on pid 1 returned: operation not permitted
process.Signal on pid 12606 returned: <nil>
process.Signal on pid 123 returned: no such process
On unix like systems (linux, freebsd, etc) os.FindProcess will never return an error. I don't know what happens on Windows. This means you won't know if the PID is correct until you try to use the *os.Process for something.
You can look at the code here.
You can also just use syscall.Kill. It amounts to less code.
killErr := syscall.Kill(pid, syscall.Signal(0))
procExists := killErr == nil
If a previously known pid is not found in the system (not sure of go functions), it means process has definitely terminated and has been joined (on Unix, with wait call) too.
But other way around is not necessarily true. Just because a pid exists, it does not quarantee it is same process as before. There are only 65535 valid pids in standard Linux for example, and they can get re-used when there is a wrap-around. However, if you check reasonably often, for practical purposes you don't need to care about this (as long as pid of wrong new process being found is not a security vulnerability or something else critical, which somebody might try to trigger intentionally for malicious purposes).
Related links (and Related questions on their right columns):
https://superuser.com/questions/135007/how-are-pids-generated
https://unix.stackexchange.com/questions/26677/will-process-ids-be-recycled-what-if-you-reach-the-maximal-id
All the answers so far are incomplete implementations. See https://github.com/shirou/gopsutil/blob/c141152a7b8f59b63e060fa8450f5cd5e7196dfb/process/process_posix.go#L73 for a more complete implementation (copied inline)
func PidExists(pid int32) (bool, error) {
if pid <= 0 {
return false, fmt.Errorf("invalid pid %v", pid)
}
proc, err := os.FindProcess(int(pid))
if err != nil {
return false, err
}
err = proc.Signal(syscall.Signal(0))
if err == nil {
return true, nil
}
if err.Error() == "os: process already finished" {
return false, nil
}
errno, ok := err.(syscall.Errno)
if !ok {
return false, err
}
switch errno {
case syscall.ESRCH:
return false, nil
case syscall.EPERM:
return true, nil
}
return false, err
}
Here is one way of how to check if a process exists/running with Golang on Windows.
We execute the command:
TASKLIST /V /NH /FI "PID eq 23232"
Which can return either:
INFO: No tasks are running which match the specified criteria.
Or if found:
Image Name PID Session Name Session# Mem Usage Status User Name CPU Time Window Title
========================= ======== ================ =========== ============ =============== ================================================== ============ ========================================================================
chrome.exe 23232 Console 1 42,472 K Unknown THANOS\MARVEL 0:00:00 N/A
Here is a function that takes advantage of this information.
func isProcessRunning(pid int) bool {
cmd := exec.Command("TASKLIST", "/FI", fmt.Sprintf("PID eq %d", pid))
result, err := cmd.Output()
if err != nil {
return false
}
return !bytes.Contains(result, []byte("No tasks are running"))
}
The best thing about this is you can find the process by other parameters too:
ImageName eq, ne Image Name String
PID eq, ne, gt, lt, ge, le Process ID, A Positive integer.
Session eq, ne, gt, lt, ge, le Any valid session number.
SessionName eq, ne String
Status eq, ne RUNNING | NOT RESPONDING | UNKNOWN
CPUTime eq, ne, gt, lt, ge, le Time hh:mm:ss
MemUsage eq, ne, gt, lt, ge, le Memory usage in KB, specify a valid integer.
Username eq, ne User name ([Domain\]User).
Services eq, ne Service Name String
Windowtitle eq, ne Window Title String
Modules eq, ne DLL Name String
On Windows checking the result of os.FindProcess() seems to be enough to check if process is running.
func isProcessRunning(pid int) bool {
_, err = os.FindProcess(pid)
if err != nil {
return false
}
if runtime.GOOS == "windows" {
return true
}
return false // further checking for other systems then Windows is not supported here
}
After searching for a few hours, the correct answer to know if a process is running on Windows is the following:
func CheckProcessLife(pid int){
cmd,_ := exec.Command("tasklist","/FI", "PID eq " + strconv.Itoa(pid)).Output()
output := string(cmd[:])
splitOutp := strings.Split(output, " ")
if !(splitOutp[1] == "no") {
time.Sleep(500 * time.Millisecond)
fmt.Println("Process is running...")
CheckProcessLife(pid)
}else{
fmt.Println("Process is no longer running.")
}
}
You can check if the process is running with his PID or directly with his name, only change this line:
cmd,_ := exec.Command("tasklist","/FI", "IMAGENAME eq yourprocessname.exe").Output()
Related
I am a beginner and am currently playing with the pubsub example from libp2p given here https://github.com/libp2p/go-libp2p/tree/master/examples/pubsub/basic-chat-with-rendezvous
I have been able to build the code and run the binary in different terminals and it works.
I am trying to automate this process from the main.go program itself where I can create a few threads to spin up new agents where they
publish messages to the network and the rest of the peers subscribe to it.
I have provided the modified code I have built currently but it doesnt seem to work. The peers cannot discover each other.
func main() {
help := flag.Bool("help", false, "Display Help")
cfg := parseFlags()
if *help {
fmt.Printf("Simple example for peer discovery using mDNS. mDNS is great when you have multiple peers in local LAN.")
fmt.Printf("Usage: \n Run './chat-with-mdns'\nor Run './chat-with-mdns -host [host] -port [port] -rendezvous [string] -pid [proto ID]'\n")
os.Exit(0)
}
fmt.Printf("[*] Listening on: %s with port: %d\n", cfg.listenHost, cfg.listenPort)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
// Spawn a thread for each iteration in the loop.
// Pass 'i' into the goroutine's function
// in order to make sure each goroutine
// uses a different value for 'i'.
wg.Add(5)
go func(i int) {
// At the end of the goroutine, tell the WaitGroup
// that another thread has completed.
defer wg.Done()
ctx := context.Background()
r := rand.Reader
// Creates a new RSA key pair for this host.
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
if err != nil {
panic(err)
}
// 0.0.0.0 will listen on any interface device.
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", cfg.listenHost, cfg.listenPort))
// libp2p.New constructs a new libp2p Host.
// Other options can be added here.
host, err := libp2p.New(
libp2p.ListenAddrs(sourceMultiAddr),
libp2p.Identity(prvKey),
)
if err != nil {
panic(err)
}
// Set a function as stream handler.
// This function is called when a peer initiates a connection and starts a stream with this peer.
host.SetStreamHandler(protocol.ID(cfg.ProtocolID), handleStream)
fmt.Printf("\n[*] Your Multiaddress Is: /ip4/%s/tcp/%v/p2p/%s\n", cfg.listenHost, cfg.listenPort, host.ID().Pretty())
peerChan := initMDNS(host, cfg.RendezvousString)
for { // allows multiple peers to join
peer := <-peerChan // will block untill we discover a peer // the code currently hangs here
fmt.Println("Found peer:", peer, ", connecting")
if err := host.Connect(ctx, peer); err != nil {
fmt.Println("Connection failed:", err)
continue
}
//** this part of the code is experimental and is not accessed by any thread yet **//
stream, err := host.NewStream(ctx, peer.ID, protocol.ID(cfg.ProtocolID))
if err != nil {
fmt.Println("Stream open failed", err)
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
go writeData(rw)
go readData(rw)
fmt.Println("Connected to:", peer)
}
//** this part of the code is experimental and is not accessed by any thread yet **//
}
}(i)
}
fmt.Println("exit")
wg.Wait()
fmt.Println("Finished for loop")
}
But this doesn't seem to work. Are there any examples I can look at currently for solving this error.
I have this function that logs the error in some cases:
func readByte(/*...*/){
// ...
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
Now, in the test file, I want to check the output error from this function:
c.Assert(OUTPUT, check.Matches, "teste")
How can I access the log? I tried to put a buffer but it didn't work. What is the right way to catch this log without change my readByte function code?
For example,
readbyte_test.go:
package main
import (
"bytes"
"fmt"
"io"
"log"
"os"
"testing"
)
func readByte( /*...*/ ) {
// ...
err := io.EOF // force an error
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
func TestReadByte(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()
readByte()
t.Log(buf.String())
}
Output:
$ go test -v readbyte_test.go
=== RUN TestReadByte
ERROR
--- PASS: TestReadByte (0.00s)
readbyte_test.go:30: 2017/05/22 16:41:00 Couldn't read first byte
PASS
ok command-line-arguments 0.004s
$
Answer for Concurrent Tests
If your test is running concurrently (for example, when testing an http Server or Client), you may encounter a race between writing to the buffer and reading from it. Instead of the buffer, we can redirect output to an os.Pipe and use a bufio.Scanner to block until output has been written by using the Scan() method.
Here is an example of creating an os.Pipe and setting the stdlib log package to use the pipe. Note my use of the testify/assert package here:
func mockLogger(t *testing.T) (*bufio.Scanner, *os.File, *os.File) {
reader, writer, err := os.Pipe()
if err != nil {
assert.Fail(t, "couldn't get os Pipe: %v", err)
}
log.SetOutput(writer)
return bufio.NewScanner(reader), reader, writer
}
The *os.File objects are returned so they can be properly closed with a deferred function. Here I'm just printing to stdout since if there was some strange error on close I personally wouldn't want to fail the test. However, this could easily be another call to t.Errorf or similar if you wanted:
func resetLogger(reader *os.File, writer *os.File) {
err := reader.Close()
if err != nil {
fmt.Println("error closing reader was ", err)
}
if err = writer.Close(); err != nil {
fmt.Println("error closing writer was ", err)
}
log.SetOutput(os.Stderr)
}
And then in your test you would have this pattern:
scanner, reader, writer := mockLogger(t) // turn this off when debugging or developing as you will miss output!
defer resetLogger(reader, writer)
// other setup as needed, getting some value for thing below
go concurrentAction()
scanner.Scan() // blocks until a new line is written to the pipe
got := scanner.Text() // the last line written to the scanner
msg := fmt.Sprintf("your log message with thing %v you care about", thing)
assert.Contains(t, got, msg)
And finally, the concurrentAction() function is calling a log function (or method if using a log.logger, the package actually behaves the same way with log.SetOutput() call above either way) like:
// doing something, getting value for thing
log.Printf("your log message with the thing %v you care about", thing)
I am really new to Golang and I have a question regarding to testing.
I had a test where I wanted to check whether the persisting of a customer in elasticsearch works or not. I've reduced the code to the critical part and posted it on github: (https://github.com/fvosberg/elastic-go-testing)
The problem is, that I have to wait for elasticsearch to index the new document, before I can search for it. Is there another option than waiting a second for this to happen? This feels very ugly, but I don't know how I can test the integration (working with elasticsearch with lowercasing the email address ...) in another way.
Are there solutions for this problem?
package main
import (
"github.com/fvosberg/elastic-go-testing/customer"
"testing"
"time"
)
func TestRegistration(t *testing.T) {
testCustomer := customer.Customer{Email: "testing#test.de"}
testCustomer.Create()
time.Sleep(time.Second * 1)
_, err := customer.FindByEmail("testing#test.de")
if err != nil {
t.Logf("Error occured: %+v\n", err)
t.Fail()
} else {
t.Log("Found customer testing#test.de")
}
}
Elasticsearch has a flush command that is useful for this situation. Since you're using the elastic project as an interface, you can use the following (where client is your ES client):
...
testCustomer.Create()
res, err := client.Flush().Do()
if err != nil {
t.Fatal(err)
}
_, err := customer.FindByEmail("testing#test.de")
...
Disclaimer: I wish you a merry XMas and I hope my question does not disturb you!
sample.go:
package main
import(
"fmt"
"os"
)
type sample struct {
value int64
}
func (s sample) useful() {
if s.value == 0 {
fmt.Println("Error: something is wrong!")
os.Exit(1)
} else {
fmt.Println("May the force be with you!")
}
}
func main() {
s := sample{42}
s.useful()
s.value = 0
s.useful()
}
// output:
// May the force be with you!
// Error: something is wrong!
// exit status 1
I did a lot of research on how to use interfaces in golang testing. But so far I was not able to wrap my head around this completely. At least I can not see how interfaces help me when I need to "mock" (apologies for using this word) golang std. library packages like "fmt".
I came up with two scenarios:
use os/exec to test the command line interface
wrap fmt package so I have control and am able to check the output strings
I do not like both scenarios:
I experience going through the actual command line a convoluted and not-performant (see below). Might have portability issues, too.
I believe this is the way to go but I fear that wrapping the fmt package might be a lot of work (at least wrapping the time package for testing turned out a non-trivial task (https://github.com/finklabs/ttime)).
Actual Question here: Is there another (better/simpler/idiomatic) way?
Note: I want to do this in pure golang, I am not interested in the next testing framework.
cli_test.go:
package main
import(
"os/exec"
"testing"
)
func TestCli(t *testing.T) {
out, err := exec.Command("go run sample.go").Output()
if err != nil {
t.Fatal(err)
}
if string(out) != "May the force be with you!\nError: this is broken and not useful!\nexit status 1" {
t.Fatal("There is something wrong with the CLI")
}
}
Chapter 11 of Kerningham's Book gives a good solution to this question.
The trick is to change the calls to fmt.Printline() to calls to
fmt.Fprint(out, ...) where out is initialised to os.Stdout
This can be overwritten in the test harness to new(bytes.Buffer) allowing the
test to capture the output.
See https://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo.go and
https://github.com/adonovan/gopl.io/blob/master/ch11/echo/echo_test.go
edited by OP...
sample.go:
package main
import(
"fmt"
"os"
"io"
)
var out io.Writer = os.Stdout // modified during testing
var exit func(code int) = os.Exit
type sample struct {
value int64
}
func (s sample) useful() {
if s.value == 0 {
fmt.Fprint(out, "Error: something is wrong!\n")
exit(1)
} else {
fmt.Fprint(out, "May the force be with you!\n")
}
}
func main() {
s := sample{42}
s.useful()
s.value = 0
s.useful()
}
// output:
// May the force be with you!
// Error: this is broken and not useful!
// exit status 1
cli_test.go:
package main
import(
"bytes"
"testing"
)
func TestUsefulPositive(t *testing.T) {
bak := out
out = new(bytes.Buffer)
defer func() { out = bak }()
s := sample{42}
s.useful()
if out.(*bytes.Buffer).String() != "May the force be with you!\n" {
t.Fatal("There is something wrong with the CLI")
}
}
func TestUsefulNegative(t *testing.T) {
bak := out
out = new(bytes.Buffer)
defer func() { out = bak }()
code := 0
osexit := exit
exit = func(c int) { code = c }
defer func() { exit = osexit }()
s := sample{0}
s.useful()
if out.(*bytes.Buffer).String() != "Error: something is wrong!\n" {
t.Fatal("There is something wrong with the CLI")
}
if code != 1 {
t.Fatal("Wrong exit code!")
}
}
Am I missing something here or are you talking of testable examples?
Basically, it works like this: In a *_test.go file, you need to adhere to the convention Example[[T][_M]] where T is a placeholder for the type and M a placeholder for the method you want to display the testable example as example code in the Godoc. If the function is just called Example(), the code will be shown as a package example.
Below the last line of the code of your example, you can put a comment like this
// Output:
// Foo
Now go test will make sure that the testable example function either exactly puts out everything below // Output: (including whitespace) or it will make the test fail.
Here is an actual example for an testable example
func ExampleMongoStore_Get() {
sessionId := "ExampleGetSession"
data, err := ms.Get(sessionId)
if err == sessionmw.ErrSessionNotFound {
fmt.Printf("Session '%s' not found\n", sessionId)
data = make(map[string]interface{})
data["foo"] = "bar"
ms.Save(sessionId, data)
}
loaded, _ := ms.Get(sessionId)
fmt.Printf("Loaded value '%s' for key '%s' in session '%s'",
loaded["foo"],
"foo", sessionId)
// Output:
// Session 'ExampleGetSession' not found
// Loaded value 'bar' for key 'foo' in session 'ExampleGetSession'
}
Edit: Have a look at the output of above example at godoc.org
We are trying to test locks. Basically, there are multiple clients trying to obtain a lock on a particular key. In the example below, we used the key "x".
I don't know how to test whether the locking is working. I can only read the logs to determine whether it is working.
The correct sequence of events should be:
client1 obtains lock on key "x"
client2 tries to obtain lock on key "x" (fmt.Println("2 getting lock")) - but is blocked and waits
client1 releases lock on key "x"
client2 obtains lock on key "x"
Q1: How could I automate the process and turn this into a test?
Q2: What are some of the tips to testing concurrency / mutex locking in general?
func TestLockUnlock(t *testing.T) {
client1, err := NewClient()
if err != nil {
t.Error("Unexpected new client error: ", err)
}
fmt.Println("1 getting lock")
id1, err := client1.Lock("x", 10*time.Second)
if err != nil {
t.Error("Unexpected lock error: ", err)
}
fmt.Println("1 got lock")
go func() {
client2, err := NewClient()
if err != nil {
t.Error("Unexpected new client error: ", err)
}
fmt.Println("2 getting lock")
id2, err := client2.Lock("x", 10*time.Second)
if err != nil {
t.Error("Unexpected lock error: ", err)
}
fmt.Println("2 got lock")
fmt.Println("2 releasing lock")
err = client2.Unlock("x", id2)
if err != nil {
t.Error("Unexpected Unlock error: ", err)
}
fmt.Println("2 released lock")
err = client2.Close()
if err != nil {
t.Error("Unexpected connection close error: ", err)
}
}()
fmt.Println("sleeping")
time.Sleep(2 * time.Second)
fmt.Println("finished sleeping")
fmt.Println("1 releasing lock")
err = client1.Unlock("x", id1)
if err != nil {
t.Error("Unexpected Unlock error: ", err)
}
fmt.Println("1 released lock")
err = client1.Close()
if err != nil {
t.Error("Unexpected connection close error: ", err)
}
time.Sleep(5 * time.Second)
}
func NewClient() *Client {
....
}
func (c *Client) Lock(lockKey string, timeout time.Duration) (lockId int64, err error){
....
}
func (c *Client) Unlock(lockKey string) err error {
....
}
Concurrency testing of lock-based code is hard, to the extent that provable-correct solutions are difficult to come by. Ad-hoc manual testing via print statements is not ideal.
There are four dynamic concurrency problems that are essentially untestable (more). Along with the testing of performance, a statistical approach is the best you can achieve via test code (e.g. establishing that the 90 percentile performance is better than 10ms or that deadlock is less than 1% likely).
This is one of the reasons that the Communicating Sequential Process (CSP) approach provided by Go is better to use than locks on share memory. Consider that your Goroutine under test provides a unit with specified behaviour. This can be tested against other Goroutines that provide the necessary test inputs via channels and monitor result outputs via channels.
With CSP, using Goroutines without any shared memory (and without any inadvertently shared memory via pointers) will guarantee that race conditions don't occur in any data accesses. Using certain proven design patterns (e.g. by Welch, Justo and WIllcock) can establish that there won't be deadlock between Goroutines. It then remains to establish that the functional behaviour is correct, for which the Goroutine test-harness mentioned above will do nicely.