You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

517 lines
12 KiB

  1. /*
  2. * Minio Cloud Storage, (C) 2016 Minio, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package cmd
  17. import (
  18. "net/url"
  19. "runtime"
  20. "sync"
  21. "testing"
  22. "time"
  23. )
  24. // Helper function to test equality of locks (without taking timing info into account)
  25. func testLockEquality(lriLeft, lriRight []lockRequesterInfo) bool {
  26. if len(lriLeft) != len(lriRight) {
  27. return false
  28. }
  29. for i := 0; i < len(lriLeft); i++ {
  30. if lriLeft[i].writer != lriRight[i].writer ||
  31. lriLeft[i].node != lriRight[i].node ||
  32. lriLeft[i].rpcPath != lriRight[i].rpcPath ||
  33. lriLeft[i].uid != lriRight[i].uid {
  34. return false
  35. }
  36. }
  37. return true
  38. }
  39. // Helper function to create a lock server for testing
  40. func createLockTestServer(t *testing.T) (string, *lockServer, string) {
  41. testPath, err := newTestConfig("us-east-1")
  42. if err != nil {
  43. t.Fatalf("unable initialize config file, %s", err)
  44. }
  45. jwt, err := newJWT(defaultJWTExpiry)
  46. if err != nil {
  47. t.Fatalf("unable to get new JWT, %s", err)
  48. }
  49. err = jwt.Authenticate(serverConfig.GetCredential().AccessKeyID, serverConfig.GetCredential().SecretAccessKey)
  50. if err != nil {
  51. t.Fatalf("unable for JWT to authenticate, %s", err)
  52. }
  53. token, err := jwt.GenerateToken(serverConfig.GetCredential().AccessKeyID)
  54. if err != nil {
  55. t.Fatalf("unable for JWT to generate token, %s", err)
  56. }
  57. locker := &lockServer{
  58. rpcPath: "rpc-path",
  59. mutex: sync.Mutex{},
  60. lockMap: make(map[string][]lockRequesterInfo),
  61. }
  62. return testPath, locker, token
  63. }
  64. // Test Lock functionality
  65. func TestLockRpcServerLock(t *testing.T) {
  66. timestamp := time.Now().UTC()
  67. testPath, locker, token := createLockTestServer(t)
  68. defer removeAll(testPath)
  69. la := LockArgs{
  70. Name: "name",
  71. Token: token,
  72. Timestamp: timestamp,
  73. Node: "node",
  74. RPCPath: "rpc-path",
  75. UID: "0123-4567",
  76. }
  77. // Claim a lock
  78. var result bool
  79. err := locker.Lock(&la, &result)
  80. if err != nil {
  81. t.Errorf("Expected %#v, got %#v", nil, err)
  82. } else {
  83. if !result {
  84. t.Errorf("Expected %#v, got %#v", true, result)
  85. } else {
  86. gotLri, _ := locker.lockMap["name"]
  87. expectedLri := []lockRequesterInfo{
  88. {
  89. writer: true,
  90. node: "node",
  91. rpcPath: "rpc-path",
  92. uid: "0123-4567",
  93. },
  94. }
  95. if !testLockEquality(expectedLri, gotLri) {
  96. t.Errorf("Expected %#v, got %#v", expectedLri, gotLri)
  97. }
  98. }
  99. }
  100. // Try to claim same lock again (will fail)
  101. la2 := LockArgs{
  102. Name: "name",
  103. Token: token,
  104. Timestamp: timestamp,
  105. Node: "node",
  106. RPCPath: "rpc-path",
  107. UID: "89ab-cdef",
  108. }
  109. err = locker.Lock(&la2, &result)
  110. if err != nil {
  111. t.Errorf("Expected %#v, got %#v", nil, err)
  112. } else {
  113. if result {
  114. t.Errorf("Expected %#v, got %#v", false, result)
  115. }
  116. }
  117. }
  118. // Test Unlock functionality
  119. func TestLockRpcServerUnlock(t *testing.T) {
  120. timestamp := time.Now().UTC()
  121. testPath, locker, token := createLockTestServer(t)
  122. defer removeAll(testPath)
  123. la := LockArgs{
  124. Name: "name",
  125. Token: token,
  126. Timestamp: timestamp,
  127. Node: "node",
  128. RPCPath: "rpc-path",
  129. UID: "0123-4567",
  130. }
  131. // First test return of error when attempting to unlock a lock that does not exist
  132. var result bool
  133. err := locker.Unlock(&la, &result)
  134. if err == nil {
  135. t.Errorf("Expected error, got %#v", nil)
  136. }
  137. // Create lock (so that we can release)
  138. err = locker.Lock(&la, &result)
  139. if err != nil {
  140. t.Errorf("Expected %#v, got %#v", nil, err)
  141. } else if !result {
  142. t.Errorf("Expected %#v, got %#v", true, result)
  143. }
  144. // Finally test successful release of lock
  145. err = locker.Unlock(&la, &result)
  146. if err != nil {
  147. t.Errorf("Expected %#v, got %#v", nil, err)
  148. } else {
  149. if !result {
  150. t.Errorf("Expected %#v, got %#v", true, result)
  151. } else {
  152. gotLri, _ := locker.lockMap["name"]
  153. expectedLri := []lockRequesterInfo(nil)
  154. if !testLockEquality(expectedLri, gotLri) {
  155. t.Errorf("Expected %#v, got %#v", expectedLri, gotLri)
  156. }
  157. }
  158. }
  159. }
  160. // Test RLock functionality
  161. func TestLockRpcServerRLock(t *testing.T) {
  162. timestamp := time.Now().UTC()
  163. testPath, locker, token := createLockTestServer(t)
  164. defer removeAll(testPath)
  165. la := LockArgs{
  166. Name: "name",
  167. Token: token,
  168. Timestamp: timestamp,
  169. Node: "node",
  170. RPCPath: "rpc-path",
  171. UID: "0123-4567",
  172. }
  173. // Claim a lock
  174. var result bool
  175. err := locker.RLock(&la, &result)
  176. if err != nil {
  177. t.Errorf("Expected %#v, got %#v", nil, err)
  178. } else {
  179. if !result {
  180. t.Errorf("Expected %#v, got %#v", true, result)
  181. } else {
  182. gotLri, _ := locker.lockMap["name"]
  183. expectedLri := []lockRequesterInfo{
  184. {
  185. writer: false,
  186. node: "node",
  187. rpcPath: "rpc-path",
  188. uid: "0123-4567",
  189. },
  190. }
  191. if !testLockEquality(expectedLri, gotLri) {
  192. t.Errorf("Expected %#v, got %#v", expectedLri, gotLri)
  193. }
  194. }
  195. }
  196. // Try to claim same again (will succeed)
  197. la2 := LockArgs{
  198. Name: "name",
  199. Token: token,
  200. Timestamp: timestamp,
  201. Node: "node",
  202. RPCPath: "rpc-path",
  203. UID: "89ab-cdef",
  204. }
  205. err = locker.RLock(&la2, &result)
  206. if err != nil {
  207. t.Errorf("Expected %#v, got %#v", nil, err)
  208. } else {
  209. if !result {
  210. t.Errorf("Expected %#v, got %#v", true, result)
  211. }
  212. }
  213. }
  214. // Test RUnlock functionality
  215. func TestLockRpcServerRUnlock(t *testing.T) {
  216. timestamp := time.Now().UTC()
  217. testPath, locker, token := createLockTestServer(t)
  218. defer removeAll(testPath)
  219. la := LockArgs{
  220. Name: "name",
  221. Token: token,
  222. Timestamp: timestamp,
  223. Node: "node",
  224. RPCPath: "rpc-path",
  225. UID: "0123-4567",
  226. }
  227. // First test return of error when attempting to unlock a read-lock that does not exist
  228. var result bool
  229. err := locker.Unlock(&la, &result)
  230. if err == nil {
  231. t.Errorf("Expected error, got %#v", nil)
  232. }
  233. // Create first lock ... (so that we can release)
  234. err = locker.RLock(&la, &result)
  235. if err != nil {
  236. t.Errorf("Expected %#v, got %#v", nil, err)
  237. } else if !result {
  238. t.Errorf("Expected %#v, got %#v", true, result)
  239. }
  240. la2 := LockArgs{
  241. Name: "name",
  242. Token: token,
  243. Timestamp: timestamp,
  244. Node: "node",
  245. RPCPath: "rpc-path",
  246. UID: "89ab-cdef",
  247. }
  248. // ... and create a second lock on same resource
  249. err = locker.RLock(&la2, &result)
  250. if err != nil {
  251. t.Errorf("Expected %#v, got %#v", nil, err)
  252. } else if !result {
  253. t.Errorf("Expected %#v, got %#v", true, result)
  254. }
  255. // Test successful release of first read lock
  256. err = locker.RUnlock(&la, &result)
  257. if err != nil {
  258. t.Errorf("Expected %#v, got %#v", nil, err)
  259. } else {
  260. if !result {
  261. t.Errorf("Expected %#v, got %#v", true, result)
  262. } else {
  263. gotLri, _ := locker.lockMap["name"]
  264. expectedLri := []lockRequesterInfo{
  265. {
  266. writer: false,
  267. node: "node",
  268. rpcPath: "rpc-path",
  269. uid: "89ab-cdef",
  270. },
  271. }
  272. if !testLockEquality(expectedLri, gotLri) {
  273. t.Errorf("Expected %#v, got %#v", expectedLri, gotLri)
  274. }
  275. }
  276. }
  277. // Finally test successful release of second (and last) read lock
  278. err = locker.RUnlock(&la2, &result)
  279. if err != nil {
  280. t.Errorf("Expected %#v, got %#v", nil, err)
  281. } else {
  282. if !result {
  283. t.Errorf("Expected %#v, got %#v", true, result)
  284. } else {
  285. gotLri, _ := locker.lockMap["name"]
  286. expectedLri := []lockRequesterInfo(nil)
  287. if !testLockEquality(expectedLri, gotLri) {
  288. t.Errorf("Expected %#v, got %#v", expectedLri, gotLri)
  289. }
  290. }
  291. }
  292. }
  293. // Test ForceUnlock functionality
  294. func TestLockRpcServerForceUnlock(t *testing.T) {
  295. timestamp := time.Now().UTC()
  296. testPath, locker, token := createLockTestServer(t)
  297. defer removeAll(testPath)
  298. laForce := LockArgs{
  299. Name: "name",
  300. Token: token,
  301. Timestamp: timestamp,
  302. Node: "node",
  303. RPCPath: "rpc-path",
  304. UID: "1234-5678",
  305. }
  306. // First test that UID should be empty
  307. var result bool
  308. err := locker.ForceUnlock(&laForce, &result)
  309. if err == nil {
  310. t.Errorf("Expected error, got %#v", nil)
  311. }
  312. // Then test force unlock of a lock that does not exist (not returning an error)
  313. laForce.UID = ""
  314. err = locker.ForceUnlock(&laForce, &result)
  315. if err != nil {
  316. t.Errorf("Expected no error, got %#v", err)
  317. }
  318. la := LockArgs{
  319. Name: "name",
  320. Token: token,
  321. Timestamp: timestamp,
  322. Node: "node",
  323. RPCPath: "rpc-path",
  324. UID: "0123-4567",
  325. }
  326. // Create lock ... (so that we can force unlock)
  327. err = locker.Lock(&la, &result)
  328. if err != nil {
  329. t.Errorf("Expected %#v, got %#v", nil, err)
  330. } else if !result {
  331. t.Errorf("Expected %#v, got %#v", true, result)
  332. }
  333. // Forcefully unlock the lock (not returning an error)
  334. err = locker.ForceUnlock(&laForce, &result)
  335. if err != nil {
  336. t.Errorf("Expected no error, got %#v", err)
  337. }
  338. // Try to get lock again (should be granted)
  339. err = locker.Lock(&la, &result)
  340. if err != nil {
  341. t.Errorf("Expected %#v, got %#v", nil, err)
  342. } else if !result {
  343. t.Errorf("Expected %#v, got %#v", true, result)
  344. }
  345. // Finally forcefully unlock the lock once again
  346. err = locker.ForceUnlock(&laForce, &result)
  347. if err != nil {
  348. t.Errorf("Expected no error, got %#v", err)
  349. }
  350. }
  351. // Test Expired functionality
  352. func TestLockRpcServerExpired(t *testing.T) {
  353. timestamp := time.Now().UTC()
  354. testPath, locker, token := createLockTestServer(t)
  355. defer removeAll(testPath)
  356. la := LockArgs{
  357. Name: "name",
  358. Token: token,
  359. Timestamp: timestamp,
  360. Node: "node",
  361. RPCPath: "rpc-path",
  362. UID: "0123-4567",
  363. }
  364. // Unknown lock at server will return expired = true
  365. var expired bool
  366. err := locker.Expired(&la, &expired)
  367. if err != nil {
  368. t.Errorf("Expected no error, got %#v", err)
  369. } else {
  370. if !expired {
  371. t.Errorf("Expected %#v, got %#v", true, expired)
  372. }
  373. }
  374. // Create lock (so that we can test that it is not expired)
  375. var result bool
  376. err = locker.Lock(&la, &result)
  377. if err != nil {
  378. t.Errorf("Expected %#v, got %#v", nil, err)
  379. } else if !result {
  380. t.Errorf("Expected %#v, got %#v", true, result)
  381. }
  382. err = locker.Expired(&la, &expired)
  383. if err != nil {
  384. t.Errorf("Expected no error, got %#v", err)
  385. } else {
  386. if expired {
  387. t.Errorf("Expected %#v, got %#v", false, expired)
  388. }
  389. }
  390. }
  391. // Test initialization of lock servers.
  392. func TestLockServers(t *testing.T) {
  393. if runtime.GOOS == "windows" {
  394. return
  395. }
  396. globalMinioHost = ""
  397. testCases := []struct {
  398. isDistXL bool
  399. srvCmdConfig serverCmdConfig
  400. totalLockServers int
  401. }{
  402. // Test - 1 one lock server initialized.
  403. {
  404. isDistXL: true,
  405. srvCmdConfig: serverCmdConfig{
  406. endpoints: []*url.URL{{
  407. Scheme: "http",
  408. Host: "localhost:9000",
  409. Path: "/mnt/disk1",
  410. }, {
  411. Scheme: "http",
  412. Host: "1.1.1.2:9000",
  413. Path: "/mnt/disk2",
  414. }, {
  415. Scheme: "http",
  416. Host: "1.1.2.1:9000",
  417. Path: "/mnt/disk3",
  418. }, {
  419. Scheme: "http",
  420. Host: "1.1.2.2:9000",
  421. Path: "/mnt/disk4",
  422. }},
  423. },
  424. totalLockServers: 1,
  425. },
  426. // Test - 2 two servers possible, 1 ignored.
  427. {
  428. isDistXL: true,
  429. srvCmdConfig: serverCmdConfig{
  430. endpoints: []*url.URL{{
  431. Scheme: "http",
  432. Host: "localhost:9000",
  433. Path: "/mnt/disk1",
  434. }, {
  435. Scheme: "http",
  436. Host: "localhost:9000",
  437. Path: "/mnt/disk2",
  438. }, {
  439. Scheme: "http",
  440. Host: "1.1.2.1:9000",
  441. Path: "/mnt/disk3",
  442. }, {
  443. Scheme: "http",
  444. Host: "1.1.2.2:9000",
  445. Path: "/mnt/disk4",
  446. }},
  447. ignoredEndpoints: []*url.URL{{
  448. Scheme: "http",
  449. Host: "localhost:9000",
  450. Path: "/mnt/disk2",
  451. }},
  452. },
  453. totalLockServers: 1,
  454. },
  455. }
  456. // Validates lock server initialization.
  457. for i, testCase := range testCases {
  458. globalIsDistXL = testCase.isDistXL
  459. lockServers := newLockServers(testCase.srvCmdConfig)
  460. if len(lockServers) != testCase.totalLockServers {
  461. t.Fatalf("Test %d: Expected total %d, got %d", i+1, testCase.totalLockServers, len(lockServers))
  462. }
  463. }
  464. }