exec_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. Copyright 2020 The Rook Authors. All rights reserved.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package exec
  14. import (
  15. "os/exec"
  16. "testing"
  17. "time"
  18. "github.com/pkg/errors"
  19. exectest "github.com/rook/rook/pkg/util/exec/test"
  20. "github.com/stretchr/testify/assert"
  21. kerrors "k8s.io/apimachinery/pkg/api/errors"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. kexec "k8s.io/utils/exec"
  24. )
  25. func Test_assertErrorType(t *testing.T) {
  26. type args struct {
  27. err error
  28. }
  29. tests := []struct {
  30. name string
  31. args args
  32. want string
  33. }{
  34. {"unknown error type", args{err: errors.New("i don't know this error")}, ""},
  35. {"exec.exitError type", args{err: &exec.ExitError{Stderr: []byte("this is an error")}}, "this is an error"},
  36. {"exec.Error type", args{err: &exec.Error{Name: "my error", Err: errors.New("this is an error")}}, "exec: \"my error\": this is an error"},
  37. }
  38. for _, tt := range tests {
  39. t.Run(tt.name, func(t *testing.T) {
  40. if got := assertErrorType(tt.args.err); got != tt.want {
  41. t.Errorf("assertErrorType() = %v, want %v", got, tt.want)
  42. }
  43. })
  44. }
  45. }
  46. // import TestMockExecHelperProcess
  47. func TestMockExecHelperProcess(t *testing.T) {
  48. exectest.TestMockExecHelperProcess(t)
  49. }
  50. func TestExtractExitCode(t *testing.T) {
  51. mockExecExitError := func(retcode int) *exec.ExitError {
  52. // we can't create an exec.ExitError directly, but we can get one by running a command that fails
  53. // use go's type assertion to be sure we are returning exactly *exec.ExitError
  54. err := exectest.MockExecCommandReturns(t, "stdout", "stderr", retcode)
  55. ee, ok := err.(*exec.ExitError)
  56. if !ok {
  57. t.Fatalf("failed to create an *exec.ExitError. instead %T", err)
  58. }
  59. return ee
  60. }
  61. expectError := true
  62. noError := false
  63. tests := []struct {
  64. name string
  65. inputErr error
  66. want int
  67. wantErr bool
  68. }{
  69. {"*exec.ExitError",
  70. mockExecExitError(3),
  71. 3, noError},
  72. /* {"exec.ExitError", // non-pointer case is impossible (won't compile) */
  73. {"*kexec.CodeExitError (pointer)",
  74. &kexec.CodeExitError{Err: errors.New("some error"), Code: 4},
  75. 4, noError},
  76. {"kexec.CodeExitError (non-pointer)",
  77. kexec.CodeExitError{Err: errors.New("some error"), Code: 5},
  78. 5, noError},
  79. {"*kerrors.StatusError",
  80. &kerrors.StatusError{ErrStatus: metav1.Status{Code: 6}},
  81. 6, noError},
  82. /* {"kerrors.StatusError", // non-pointer case is impossible (won't compile) */
  83. {"unknown error type with error code extractable from error message",
  84. errors.New("command terminated with exit code 7"),
  85. 7, noError},
  86. {"unknown error type with no extractable error code",
  87. errors.New("command with no extractable error code even with an int here: 8"),
  88. -1, expectError},
  89. }
  90. for _, tt := range tests {
  91. t.Run(tt.name, func(t *testing.T) {
  92. got, err := ExtractExitCode(tt.inputErr)
  93. if (err != nil) != tt.wantErr {
  94. t.Errorf("ExtractExitCode() error = %v, wantErr %v", err, tt.wantErr)
  95. return
  96. }
  97. if got != tt.want {
  98. t.Errorf("ExtractExitCode() = %v, want %v", got, tt.want)
  99. }
  100. })
  101. }
  102. }
  103. func TestFakeTimeoutError(t *testing.T) {
  104. assert.True(t, IsTimeout(exectest.FakeTimeoutError("blah")))
  105. assert.True(t, IsTimeout(exectest.FakeTimeoutError("")))
  106. }
  107. func TestExecuteCommandWithTimeout(t *testing.T) {
  108. type args struct {
  109. timeout time.Duration
  110. command string
  111. stdin *string
  112. arg []string
  113. }
  114. testString := "hello"
  115. tests := []struct {
  116. name string
  117. args args
  118. want string
  119. wantErr bool
  120. }{
  121. {
  122. name: "test stdin",
  123. args: args{
  124. timeout: 30 * time.Second,
  125. command: "cat",
  126. stdin: &testString,
  127. arg: []string{},
  128. },
  129. want: testString,
  130. wantErr: false,
  131. },
  132. {
  133. name: "test nil stdin",
  134. args: args{
  135. timeout: 30 * time.Second,
  136. command: "echo",
  137. stdin: nil,
  138. arg: []string{testString},
  139. },
  140. want: testString,
  141. wantErr: false,
  142. },
  143. {
  144. name: "test timeout",
  145. args: args{
  146. timeout: 0 * time.Second,
  147. command: "cat",
  148. stdin: &testString,
  149. arg: []string{},
  150. },
  151. want: "",
  152. wantErr: true,
  153. },
  154. }
  155. for _, tt := range tests {
  156. t.Run(tt.name, func(t *testing.T) {
  157. got, err := executeCommandWithTimeout(tt.args.timeout, tt.args.command, tt.args.stdin, tt.args.arg...)
  158. if (err != nil) != tt.wantErr {
  159. t.Errorf("executeCommandWithTimeout() error = %v, wantErr %v", err, tt.wantErr)
  160. return
  161. }
  162. if got != tt.want {
  163. t.Errorf("executeCommandWithTimeout() = %v, want %v", got, tt.want)
  164. }
  165. })
  166. }
  167. }