github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/fs/rc/internal_test.go (about) 1 package rc 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "runtime" 10 "strings" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/rclone/rclone/fs" 17 "github.com/rclone/rclone/fs/config/obscure" 18 ) 19 20 func TestMain(m *testing.M) { 21 // Pretend to be rclone version if we have a version string parameter 22 if os.Args[len(os.Args)-1] == "version" { 23 fmt.Printf("rclone %s\n", fs.Version) 24 os.Exit(0) 25 } 26 // Pretend to error if we have an unknown command 27 if os.Args[len(os.Args)-1] == "unknown_command" { 28 fmt.Printf("rclone %s\n", fs.Version) 29 fmt.Fprintf(os.Stderr, "Unknown command\n") 30 os.Exit(1) 31 } 32 os.Exit(m.Run()) 33 } 34 35 func TestInternalNoop(t *testing.T) { 36 call := Calls.Get("rc/noop") 37 assert.NotNil(t, call) 38 in := Params{ 39 "String": "hello", 40 "Int": 42, 41 } 42 out, err := call.Fn(context.Background(), in) 43 require.NoError(t, err) 44 require.NotNil(t, out) 45 assert.Equal(t, in, out) 46 } 47 48 func TestInternalError(t *testing.T) { 49 call := Calls.Get("rc/error") 50 assert.NotNil(t, call) 51 in := Params{} 52 out, err := call.Fn(context.Background(), in) 53 require.Error(t, err) 54 require.Nil(t, out) 55 } 56 57 func TestInternalList(t *testing.T) { 58 call := Calls.Get("rc/list") 59 assert.NotNil(t, call) 60 in := Params{} 61 out, err := call.Fn(context.Background(), in) 62 require.NoError(t, err) 63 require.NotNil(t, out) 64 assert.Equal(t, Params{"commands": Calls.List()}, out) 65 } 66 67 func TestCorePid(t *testing.T) { 68 call := Calls.Get("core/pid") 69 assert.NotNil(t, call) 70 in := Params{} 71 out, err := call.Fn(context.Background(), in) 72 require.NoError(t, err) 73 require.NotNil(t, out) 74 pid := out["pid"] 75 assert.NotEqual(t, nil, pid) 76 _, ok := pid.(int) 77 assert.Equal(t, true, ok) 78 } 79 80 func TestCoreMemstats(t *testing.T) { 81 call := Calls.Get("core/memstats") 82 assert.NotNil(t, call) 83 in := Params{} 84 out, err := call.Fn(context.Background(), in) 85 require.NoError(t, err) 86 require.NotNil(t, out) 87 sys := out["Sys"] 88 assert.NotEqual(t, nil, sys) 89 _, ok := sys.(uint64) 90 assert.Equal(t, true, ok) 91 } 92 93 func TestCoreGC(t *testing.T) { 94 call := Calls.Get("core/gc") 95 assert.NotNil(t, call) 96 in := Params{} 97 out, err := call.Fn(context.Background(), in) 98 require.NoError(t, err) 99 require.Nil(t, out) 100 assert.Equal(t, Params(nil), out) 101 } 102 103 func TestCoreVersion(t *testing.T) { 104 call := Calls.Get("core/version") 105 assert.NotNil(t, call) 106 in := Params{} 107 out, err := call.Fn(context.Background(), in) 108 require.NoError(t, err) 109 require.NotNil(t, out) 110 assert.Equal(t, fs.Version, out["version"]) 111 assert.Equal(t, runtime.GOOS, out["os"]) 112 assert.Equal(t, runtime.GOARCH, out["arch"]) 113 assert.Equal(t, runtime.Version(), out["goVersion"]) 114 _ = out["isGit"].(bool) 115 v := out["decomposed"].([]int64) 116 assert.True(t, len(v) >= 2) 117 } 118 119 func TestCoreObscure(t *testing.T) { 120 call := Calls.Get("core/obscure") 121 assert.NotNil(t, call) 122 in := Params{ 123 "clear": "potato", 124 } 125 out, err := call.Fn(context.Background(), in) 126 require.NoError(t, err) 127 require.NotNil(t, out) 128 assert.Equal(t, in["clear"], obscure.MustReveal(out["obscured"].(string))) 129 } 130 131 func TestCoreQuit(t *testing.T) { 132 //The call should return an error if param exitCode is not parsed to int 133 call := Calls.Get("core/quit") 134 assert.NotNil(t, call) 135 in := Params{ 136 "exitCode": "potato", 137 } 138 _, err := call.Fn(context.Background(), in) 139 require.Error(t, err) 140 } 141 142 // core/command: Runs a raw rclone command 143 func TestCoreCommand(t *testing.T) { 144 call := Calls.Get("core/command") 145 146 test := func(command string, returnType string, wantOutput string, fail bool) { 147 var rec = httptest.NewRecorder() 148 var w http.ResponseWriter = rec 149 150 in := Params{ 151 "command": command, 152 "opt": map[string]string{}, 153 "arg": []string{}, 154 "_response": w, 155 } 156 if returnType != "" { 157 in["returnType"] = returnType 158 } else { 159 returnType = "COMBINED_OUTPUT" 160 } 161 stream := strings.HasPrefix(returnType, "STREAM") 162 got, err := call.Fn(context.Background(), in) 163 if stream && fail { 164 assert.Error(t, err) 165 } else { 166 assert.NoError(t, err) 167 } 168 169 if !stream { 170 assert.Equal(t, wantOutput, got["result"]) 171 assert.Equal(t, fail, got["error"]) 172 } else { 173 assert.Equal(t, wantOutput, rec.Body.String()) 174 } 175 assert.Equal(t, http.StatusOK, rec.Result().StatusCode) 176 } 177 178 version := fmt.Sprintf("rclone %s\n", fs.Version) 179 errorString := "Unknown command\n" 180 t.Run("OK", func(t *testing.T) { 181 test("version", "", version, false) 182 }) 183 t.Run("Fail", func(t *testing.T) { 184 test("unknown_command", "", version+errorString, true) 185 }) 186 t.Run("Combined", func(t *testing.T) { 187 test("unknown_command", "COMBINED_OUTPUT", version+errorString, true) 188 }) 189 t.Run("Stderr", func(t *testing.T) { 190 test("unknown_command", "STREAM_ONLY_STDERR", errorString, true) 191 }) 192 t.Run("Stdout", func(t *testing.T) { 193 test("unknown_command", "STREAM_ONLY_STDOUT", version, true) 194 }) 195 t.Run("Stream", func(t *testing.T) { 196 test("unknown_command", "STREAM", version+errorString, true) 197 }) 198 }