environment_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. // environment_test tests the use and precedence of environment variables
  2. //
  3. // The tests rely on functions defined in cmdtest_test.go
  4. package cmdtest
  5. import (
  6. "os"
  7. "runtime"
  8. "testing"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. )
  12. // TestCmdTest demonstrates and verifies the test functions for end-to-end testing of rclone
  13. func TestEnvironmentVariables(t *testing.T) {
  14. createTestEnvironment(t)
  15. testdataPath := createSimpleTestData(t)
  16. // Non backend flags
  17. // =================
  18. // First verify default behaviour of the implicit max_depth=-1
  19. env := ""
  20. out, err := rcloneEnv(env, "lsl", testFolder)
  21. //t.Logf("\n" + out)
  22. if assert.NoError(t, err) {
  23. assert.Contains(t, out, "rclone.config") // depth 1
  24. assert.Contains(t, out, "file1.txt") // depth 2
  25. assert.Contains(t, out, "fileA1.txt") // depth 3
  26. assert.Contains(t, out, "fileAA1.txt") // depth 4
  27. }
  28. // Test of flag.Value
  29. env = "RCLONE_MAX_DEPTH=2"
  30. out, err = rcloneEnv(env, "lsl", testFolder)
  31. if assert.NoError(t, err) {
  32. assert.Contains(t, out, "file1.txt") // depth 2
  33. assert.NotContains(t, out, "fileA1.txt") // depth 3
  34. }
  35. // Test of flag.Changed (tests #5341 Issue1)
  36. env = "RCLONE_LOG_LEVEL=DEBUG"
  37. out, err = rcloneEnv(env, "version", "--quiet")
  38. if assert.Error(t, err) {
  39. assert.Contains(t, out, " DEBUG : ")
  40. assert.Contains(t, out, "Can't set -q and --log-level")
  41. assert.Contains(t, "exit status 1", err.Error())
  42. }
  43. // Test of flag.DefValue
  44. env = "RCLONE_STATS=173ms"
  45. out, err = rcloneEnv(env, "help", "flags")
  46. if assert.NoError(t, err) {
  47. assert.Contains(t, out, "(default 173ms)")
  48. }
  49. // Test of command line flags overriding environment flags
  50. env = "RCLONE_MAX_DEPTH=2"
  51. out, err = rcloneEnv(env, "lsl", testFolder, "--max-depth", "3")
  52. if assert.NoError(t, err) {
  53. assert.Contains(t, out, "fileA1.txt") // depth 3
  54. assert.NotContains(t, out, "fileAA1.txt") // depth 4
  55. }
  56. // Test of debug logging while initialising flags from environment (tests #5241 Enhance1)
  57. env = "RCLONE_STATS=173ms"
  58. out, err = rcloneEnv(env, "version", "-vv")
  59. if assert.NoError(t, err) {
  60. assert.Contains(t, out, " DEBUG : ")
  61. assert.Contains(t, out, "--stats")
  62. assert.Contains(t, out, "173ms")
  63. assert.Contains(t, out, "RCLONE_STATS=")
  64. }
  65. // Backend flags and remote name
  66. // - The listremotes command includes names from environment variables,
  67. // the part between "RCLONE_CONFIG_" and "_TYPE", converted to lowercase.
  68. // - When using a remote created from env, e.g. with lsd command,
  69. // the name is case insensitive in contrast to remotes in config file
  70. // (fs.ConfigToEnv converts to uppercase before checking environment).
  71. // - Previously using a remote created from env, e.g. with lsd command,
  72. // would not be possible for remotes with '-' in names, and remote names
  73. // with '_' could be referred to with both '-' and '_', because any '-'
  74. // were replaced with '_' before lookup.
  75. // ===================================
  76. env = "RCLONE_CONFIG_MY-LOCAL_TYPE=local"
  77. out, err = rcloneEnv(env, "listremotes")
  78. if assert.NoError(t, err) {
  79. assert.Contains(t, out, "my-local:")
  80. }
  81. out, err = rcloneEnv(env, "lsl", "my-local:"+testFolder)
  82. if assert.NoError(t, err) {
  83. assert.Contains(t, out, "rclone.config")
  84. assert.Contains(t, out, "file1.txt")
  85. assert.Contains(t, out, "fileA1.txt")
  86. assert.Contains(t, out, "fileAA1.txt")
  87. }
  88. out, err = rcloneEnv(env, "lsl", "mY-LoCaL:"+testFolder)
  89. if assert.NoError(t, err) {
  90. assert.Contains(t, out, "rclone.config")
  91. assert.Contains(t, out, "file1.txt")
  92. assert.Contains(t, out, "fileA1.txt")
  93. assert.Contains(t, out, "fileAA1.txt")
  94. }
  95. out, err = rcloneEnv(env, "lsl", "my_local:"+testFolder)
  96. if assert.Error(t, err) {
  97. assert.Contains(t, out, "Failed to create file system")
  98. }
  99. env = "RCLONE_CONFIG_MY_LOCAL_TYPE=local"
  100. out, err = rcloneEnv(env, "listremotes")
  101. if assert.NoError(t, err) {
  102. assert.Contains(t, out, "my_local:")
  103. }
  104. out, err = rcloneEnv(env, "lsl", "my_local:"+testFolder)
  105. if assert.NoError(t, err) {
  106. assert.Contains(t, out, "rclone.config")
  107. assert.Contains(t, out, "file1.txt")
  108. assert.Contains(t, out, "fileA1.txt")
  109. assert.Contains(t, out, "fileAA1.txt")
  110. }
  111. out, err = rcloneEnv(env, "lsl", "my-local:"+testFolder)
  112. if assert.Error(t, err) {
  113. assert.Contains(t, out, "Failed to create file system")
  114. }
  115. // Backend flags and option precedence
  116. // ===================================
  117. // Test approach:
  118. // Verify no symlink warning when skip_links=true one the level with highest precedence
  119. // and skip_links=false on all levels with lower precedence
  120. //
  121. // Reference: https://rclone.org/docs/#precedence
  122. // Create a symlink in test data
  123. err = os.Symlink(testdataPath+"/folderA", testdataPath+"/symlinkA")
  124. if runtime.GOOS == "windows" {
  125. errNote := "The policy settings on Windows often prohibit the creation of symlinks due to security issues.\n"
  126. errNote += "You can safely ignore this test, if your change didn't affect environment variables."
  127. require.NoError(t, err, errNote)
  128. } else {
  129. require.NoError(t, err)
  130. }
  131. // Create a local remote with explicit skip_links=false
  132. out, err = rclone("config", "create", "myLocal", "local", "skip_links", "false")
  133. if assert.NoError(t, err) {
  134. assert.Contains(t, out, "[myLocal]")
  135. assert.Contains(t, out, "type = local")
  136. assert.Contains(t, out, "skip_links = false")
  137. }
  138. // Verify symlink warning when skip_links=false on all levels
  139. env = "RCLONE_SKIP_LINKS=false;RCLONE_LOCAL_SKIP_LINKS=false;RCLONE_CONFIG_MYLOCAL_SKIP_LINKS=false"
  140. out, err = rcloneEnv(env, "lsd", "myLocal,skip_links=false:"+testdataPath, "--skip-links=false")
  141. //t.Logf("\n" + out)
  142. if assert.NoError(t, err) {
  143. assert.Contains(t, out, "NOTICE: symlinkA:")
  144. assert.Contains(t, out, "folderA")
  145. }
  146. // Test precedence of connection strings
  147. env = "RCLONE_SKIP_LINKS=false;RCLONE_LOCAL_SKIP_LINKS=false;RCLONE_CONFIG_MYLOCAL_SKIP_LINKS=false"
  148. out, err = rcloneEnv(env, "lsd", "myLocal,skip_links:"+testdataPath, "--skip-links=false")
  149. if assert.NoError(t, err) {
  150. assert.NotContains(t, out, "symlinkA")
  151. assert.Contains(t, out, "folderA")
  152. }
  153. // Test precedence of command line flags
  154. env = "RCLONE_SKIP_LINKS=false;RCLONE_LOCAL_SKIP_LINKS=false;RCLONE_CONFIG_MYLOCAL_SKIP_LINKS=false"
  155. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath, "--skip-links")
  156. if assert.NoError(t, err) {
  157. assert.NotContains(t, out, "symlinkA")
  158. assert.Contains(t, out, "folderA")
  159. }
  160. // Test precedence of remote specific environment variables (tests #5341 Issue2)
  161. env = "RCLONE_SKIP_LINKS=false;RCLONE_LOCAL_SKIP_LINKS=false;RCLONE_CONFIG_MYLOCAL_SKIP_LINKS=true"
  162. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath)
  163. if assert.NoError(t, err) {
  164. assert.NotContains(t, out, "symlinkA")
  165. assert.Contains(t, out, "folderA")
  166. }
  167. // Test precedence of backend specific environment variables (tests #5341 Issue3)
  168. env = "RCLONE_SKIP_LINKS=false;RCLONE_LOCAL_SKIP_LINKS=true"
  169. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath)
  170. if assert.NoError(t, err) {
  171. assert.NotContains(t, out, "symlinkA")
  172. assert.Contains(t, out, "folderA")
  173. }
  174. // Test precedence of backend generic environment variables
  175. env = "RCLONE_SKIP_LINKS=true"
  176. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath)
  177. if assert.NoError(t, err) {
  178. assert.NotContains(t, out, "symlinkA")
  179. assert.Contains(t, out, "folderA")
  180. }
  181. // Recreate the test remote with explicit skip_links=true
  182. out, err = rclone("config", "create", "myLocal", "local", "skip_links", "true")
  183. if assert.NoError(t, err) {
  184. assert.Contains(t, out, "[myLocal]")
  185. assert.Contains(t, out, "type = local")
  186. assert.Contains(t, out, "skip_links = true")
  187. }
  188. // Test precedence of config file options
  189. env = ""
  190. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath)
  191. if assert.NoError(t, err) {
  192. assert.NotContains(t, out, "symlinkA")
  193. assert.Contains(t, out, "folderA")
  194. }
  195. // Recreate the test remote with rclone defaults, that is implicit skip_links=false
  196. out, err = rclone("config", "create", "myLocal", "local")
  197. if assert.NoError(t, err) {
  198. assert.Contains(t, out, "[myLocal]")
  199. assert.Contains(t, out, "type = local")
  200. assert.NotContains(t, out, "skip_links")
  201. }
  202. // Verify the rclone default value (implicit skip_links=false)
  203. env = ""
  204. out, err = rcloneEnv(env, "lsd", "myLocal:"+testdataPath)
  205. if assert.NoError(t, err) {
  206. assert.Contains(t, out, "NOTICE: symlinkA:")
  207. assert.Contains(t, out, "folderA")
  208. }
  209. // Display of backend defaults (tests #4659)
  210. //------------------------------------------
  211. env = "RCLONE_DRIVE_CHUNK_SIZE=111M"
  212. out, err = rcloneEnv(env, "help", "flags")
  213. if assert.NoError(t, err) {
  214. assert.Regexp(t, "--drive-chunk-size[^\\(]+\\(default 111M\\)", out)
  215. }
  216. // Options on referencing remotes (alias, crypt, etc.)
  217. //----------------------------------------------------
  218. // Create alias remote on myLocal having implicit skip_links=false
  219. out, err = rclone("config", "create", "myAlias", "alias", "remote", "myLocal:"+testdataPath)
  220. if assert.NoError(t, err) {
  221. assert.Contains(t, out, "[myAlias]")
  222. assert.Contains(t, out, "type = alias")
  223. assert.Contains(t, out, "remote = myLocal:")
  224. }
  225. // Verify symlink warnings on the alias
  226. env = ""
  227. out, err = rcloneEnv(env, "lsd", "myAlias:")
  228. if assert.NoError(t, err) {
  229. assert.Contains(t, out, "NOTICE: symlinkA:")
  230. assert.Contains(t, out, "folderA")
  231. }
  232. // Test backend generic flags
  233. // having effect on the underlying local remote
  234. env = "RCLONE_SKIP_LINKS=true"
  235. out, err = rcloneEnv(env, "lsd", "myAlias:")
  236. if assert.NoError(t, err) {
  237. assert.NotContains(t, out, "symlinkA")
  238. assert.Contains(t, out, "folderA")
  239. }
  240. // Test backend specific flags
  241. // having effect on the underlying local remote
  242. env = "RCLONE_LOCAL_SKIP_LINKS=true"
  243. out, err = rcloneEnv(env, "lsd", "myAlias:")
  244. if assert.NoError(t, err) {
  245. assert.NotContains(t, out, "symlinkA")
  246. assert.Contains(t, out, "folderA")
  247. }
  248. // Test remote specific flags
  249. // having no effect unless supported by the immediate remote (alias)
  250. env = "RCLONE_CONFIG_MYALIAS_SKIP_LINKS=true"
  251. out, err = rcloneEnv(env, "lsd", "myAlias:")
  252. if assert.NoError(t, err) {
  253. assert.Contains(t, out, "NOTICE: symlinkA:")
  254. assert.Contains(t, out, "folderA")
  255. }
  256. env = "RCLONE_CONFIG_MYALIAS_REMOTE=" + "myLocal:" + testdataPath + "/folderA"
  257. out, err = rcloneEnv(env, "lsl", "myAlias:")
  258. if assert.NoError(t, err) {
  259. assert.Contains(t, out, "fileA1.txt")
  260. assert.NotContains(t, out, "fileB1.txt")
  261. }
  262. // Test command line flags
  263. // having effect on the underlying local remote
  264. env = ""
  265. out, err = rcloneEnv(env, "lsd", "myAlias:", "--skip-links")
  266. if assert.NoError(t, err) {
  267. assert.NotContains(t, out, "symlinkA")
  268. assert.Contains(t, out, "folderA")
  269. }
  270. // Test connection specific flags
  271. // having no effect unless supported by the immediate remote (alias)
  272. env = ""
  273. out, err = rcloneEnv(env, "lsd", "myAlias,skip_links:")
  274. if assert.NoError(t, err) {
  275. assert.Contains(t, out, "NOTICE: symlinkA:")
  276. assert.Contains(t, out, "folderA")
  277. }
  278. env = ""
  279. out, err = rcloneEnv(env, "lsl", "myAlias,remote='myLocal:"+testdataPath+"/folderA':", "-vv")
  280. if assert.NoError(t, err) {
  281. assert.Contains(t, out, "fileA1.txt")
  282. assert.NotContains(t, out, "fileB1.txt")
  283. }
  284. }