PageRenderTime 25ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/api_unit_test.go

https://gitlab.com/Izquierdo/minio-go
Go | 373 lines | 307 code | 33 blank | 33 comment | 112 complexity | 000faf110770706a4c88473fc4d68671 MD5 | raw file
  1. /*
  2. * Minio Go Library for Amazon S3 Compatible Cloud Storage (C) 2015 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 minio
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io"
  21. "io/ioutil"
  22. "net/http"
  23. "net/url"
  24. "os"
  25. "strings"
  26. "testing"
  27. )
  28. type customReader struct{}
  29. func (c *customReader) Read(p []byte) (n int, err error) {
  30. return 0, nil
  31. }
  32. func (c *customReader) Size() (n int64) {
  33. return 10
  34. }
  35. // Tests getReaderSize() for various Reader types.
  36. func TestGetReaderSize(t *testing.T) {
  37. var reader io.Reader
  38. size, err := getReaderSize(reader)
  39. if err != nil {
  40. t.Fatal("Error:", err)
  41. }
  42. if size != -1 {
  43. t.Fatal("Reader shouldn't have any length.")
  44. }
  45. bytesReader := bytes.NewReader([]byte("Hello World"))
  46. size, err = getReaderSize(bytesReader)
  47. if err != nil {
  48. t.Fatal("Error:", err)
  49. }
  50. if size != int64(len("Hello World")) {
  51. t.Fatalf("Reader length doesn't match got: %v, want: %v", size, len("Hello World"))
  52. }
  53. size, err = getReaderSize(new(customReader))
  54. if err != nil {
  55. t.Fatal("Error:", err)
  56. }
  57. if size != int64(10) {
  58. t.Fatalf("Reader length doesn't match got: %v, want: %v", size, 10)
  59. }
  60. stringsReader := strings.NewReader("Hello World")
  61. size, err = getReaderSize(stringsReader)
  62. if err != nil {
  63. t.Fatal("Error:", err)
  64. }
  65. if size != int64(len("Hello World")) {
  66. t.Fatalf("Reader length doesn't match got: %v, want: %v", size, len("Hello World"))
  67. }
  68. // Create request channel.
  69. reqCh := make(chan readRequest)
  70. // Create response channel.
  71. resCh := make(chan readResponse)
  72. // Create done channel.
  73. doneCh := make(chan struct{})
  74. // objectInfo.
  75. objectInfo := ObjectInfo{Size: 10}
  76. objectReader := newObject(reqCh, resCh, doneCh, objectInfo)
  77. defer objectReader.Close()
  78. size, err = getReaderSize(objectReader)
  79. if err != nil {
  80. t.Fatal("Error:", err)
  81. }
  82. if size != int64(10) {
  83. t.Fatalf("Reader length doesn't match got: %v, want: %v", size, 10)
  84. }
  85. fileReader, err := ioutil.TempFile(os.TempDir(), "prefix")
  86. if err != nil {
  87. t.Fatal("Error:", err)
  88. }
  89. defer fileReader.Close()
  90. defer os.RemoveAll(fileReader.Name())
  91. size, err = getReaderSize(fileReader)
  92. if err != nil {
  93. t.Fatal("Error:", err)
  94. }
  95. if size == -1 {
  96. t.Fatal("Reader length for file cannot be -1.")
  97. }
  98. // Verify for standard input, output and error file descriptors.
  99. size, err = getReaderSize(os.Stdin)
  100. if err != nil {
  101. t.Fatal("Error:", err)
  102. }
  103. if size != -1 {
  104. t.Fatal("Stdin should have length of -1.")
  105. }
  106. size, err = getReaderSize(os.Stdout)
  107. if err != nil {
  108. t.Fatal("Error:", err)
  109. }
  110. if size != -1 {
  111. t.Fatal("Stdout should have length of -1.")
  112. }
  113. size, err = getReaderSize(os.Stderr)
  114. if err != nil {
  115. t.Fatal("Error:", err)
  116. }
  117. if size != -1 {
  118. t.Fatal("Stderr should have length of -1.")
  119. }
  120. file, err := os.Open(os.TempDir())
  121. if err != nil {
  122. t.Fatal("Error:", err)
  123. }
  124. defer file.Close()
  125. _, err = getReaderSize(file)
  126. if err == nil {
  127. t.Fatal("Input file as directory should throw an error.")
  128. }
  129. }
  130. // Tests valid hosts for location.
  131. func TestValidBucketLocation(t *testing.T) {
  132. s3Hosts := []struct {
  133. bucketLocation string
  134. endpoint string
  135. }{
  136. {"us-east-1", "s3.amazonaws.com"},
  137. {"unknown", "s3.amazonaws.com"},
  138. {"ap-southeast-1", "s3-ap-southeast-1.amazonaws.com"},
  139. }
  140. for _, s3Host := range s3Hosts {
  141. endpoint := getS3Endpoint(s3Host.bucketLocation)
  142. if endpoint != s3Host.endpoint {
  143. t.Fatal("Error: invalid bucket location", endpoint)
  144. }
  145. }
  146. }
  147. // Tests temp file.
  148. func TestTempFile(t *testing.T) {
  149. tmpFile, err := newTempFile("testing")
  150. if err != nil {
  151. t.Fatal("Error:", err)
  152. }
  153. fileName := tmpFile.Name()
  154. // Closing temporary file purges the file.
  155. err = tmpFile.Close()
  156. if err != nil {
  157. t.Fatal("Error:", err)
  158. }
  159. st, err := os.Stat(fileName)
  160. if err != nil && !os.IsNotExist(err) {
  161. t.Fatal("Error:", err)
  162. }
  163. if err == nil && st != nil {
  164. t.Fatal("Error: file should be deleted and should not exist.")
  165. }
  166. }
  167. // Tests url encoding.
  168. func TestEncodeURL2Path(t *testing.T) {
  169. type urlStrings struct {
  170. objName string
  171. encodedObjName string
  172. }
  173. bucketName := "bucketName"
  174. want := []urlStrings{
  175. {
  176. objName: "本語",
  177. encodedObjName: "%E6%9C%AC%E8%AA%9E",
  178. },
  179. {
  180. objName: "本語.1",
  181. encodedObjName: "%E6%9C%AC%E8%AA%9E.1",
  182. },
  183. {
  184. objName: ">123>3123123",
  185. encodedObjName: "%3E123%3E3123123",
  186. },
  187. {
  188. objName: "test 1 2.txt",
  189. encodedObjName: "test%201%202.txt",
  190. },
  191. {
  192. objName: "test++ 1.txt",
  193. encodedObjName: "test%2B%2B%201.txt",
  194. },
  195. }
  196. for _, o := range want {
  197. u, err := url.Parse(fmt.Sprintf("https://%s.s3.amazonaws.com/%s", bucketName, o.objName))
  198. if err != nil {
  199. t.Fatal("Error:", err)
  200. }
  201. urlPath := "/" + bucketName + "/" + o.encodedObjName
  202. if urlPath != encodeURL2Path(u) {
  203. t.Fatal("Error")
  204. }
  205. }
  206. }
  207. // Tests error response structure.
  208. func TestErrorResponse(t *testing.T) {
  209. var err error
  210. err = ErrorResponse{
  211. Code: "Testing",
  212. }
  213. errResp := ToErrorResponse(err)
  214. if errResp.Code != "Testing" {
  215. t.Fatal("Type conversion failed, we have an empty struct.")
  216. }
  217. // Test http response decoding.
  218. var httpResponse *http.Response
  219. // Set empty variables
  220. httpResponse = nil
  221. var bucketName, objectName string
  222. // Should fail with invalid argument.
  223. err = httpRespToErrorResponse(httpResponse, bucketName, objectName)
  224. errResp = ToErrorResponse(err)
  225. if errResp.Code != "InvalidArgument" {
  226. t.Fatal("Empty response input should return invalid argument.")
  227. }
  228. }
  229. // Tests signature calculation.
  230. func TestSignatureCalculation(t *testing.T) {
  231. req, err := http.NewRequest("GET", "https://s3.amazonaws.com", nil)
  232. if err != nil {
  233. t.Fatal("Error:", err)
  234. }
  235. req = signV4(*req, "", "", "us-east-1")
  236. if req.Header.Get("Authorization") != "" {
  237. t.Fatal("Error: anonymous credentials should not have Authorization header.")
  238. }
  239. req = preSignV4(*req, "", "", "us-east-1", 0)
  240. if strings.Contains(req.URL.RawQuery, "X-Amz-Signature") {
  241. t.Fatal("Error: anonymous credentials should not have Signature query resource.")
  242. }
  243. req = signV2(*req, "", "")
  244. if req.Header.Get("Authorization") != "" {
  245. t.Fatal("Error: anonymous credentials should not have Authorization header.")
  246. }
  247. req = preSignV2(*req, "", "", 0)
  248. if strings.Contains(req.URL.RawQuery, "Signature") {
  249. t.Fatal("Error: anonymous credentials should not have Signature query resource.")
  250. }
  251. req = signV4(*req, "ACCESS-KEY", "SECRET-KEY", "us-east-1")
  252. if req.Header.Get("Authorization") == "" {
  253. t.Fatal("Error: normal credentials should have Authorization header.")
  254. }
  255. req = preSignV4(*req, "ACCESS-KEY", "SECRET-KEY", "us-east-1", 0)
  256. if !strings.Contains(req.URL.RawQuery, "X-Amz-Signature") {
  257. t.Fatal("Error: normal credentials should have Signature query resource.")
  258. }
  259. req = signV2(*req, "ACCESS-KEY", "SECRET-KEY")
  260. if req.Header.Get("Authorization") == "" {
  261. t.Fatal("Error: normal credentials should have Authorization header.")
  262. }
  263. req = preSignV2(*req, "ACCESS-KEY", "SECRET-KEY", 0)
  264. if !strings.Contains(req.URL.RawQuery, "Signature") {
  265. t.Fatal("Error: normal credentials should not have Signature query resource.")
  266. }
  267. }
  268. // Tests signature type.
  269. func TestSignatureType(t *testing.T) {
  270. clnt := Client{}
  271. if !clnt.signature.isV4() {
  272. t.Fatal("Error")
  273. }
  274. clnt.signature = SignatureV2
  275. if !clnt.signature.isV2() {
  276. t.Fatal("Error")
  277. }
  278. if clnt.signature.isV4() {
  279. t.Fatal("Error")
  280. }
  281. clnt.signature = SignatureV4
  282. if !clnt.signature.isV4() {
  283. t.Fatal("Error")
  284. }
  285. }
  286. // Tests bucket policy types.
  287. func TestBucketPolicyTypes(t *testing.T) {
  288. want := map[string]bool{
  289. "none": true,
  290. "readonly": true,
  291. "writeonly": true,
  292. "readwrite": true,
  293. "invalid": false,
  294. }
  295. for bucketPolicy, ok := range want {
  296. if BucketPolicy(bucketPolicy).isValidBucketPolicy() != ok {
  297. t.Fatal("Error")
  298. }
  299. }
  300. }
  301. // Tests optimal part size.
  302. func TestPartSize(t *testing.T) {
  303. totalPartsCount, partSize, lastPartSize, err := optimalPartInfo(5000000000000000000)
  304. if err == nil {
  305. t.Fatal("Error: should fail")
  306. }
  307. totalPartsCount, partSize, lastPartSize, err = optimalPartInfo(5497558138880)
  308. if err != nil {
  309. t.Fatal("Error: ", err)
  310. }
  311. if totalPartsCount != 9987 {
  312. t.Fatalf("Error: expecting total parts count of 9987: got %v instead", totalPartsCount)
  313. }
  314. if partSize != 550502400 {
  315. t.Fatalf("Error: expecting part size of 550502400: got %v instead", partSize)
  316. }
  317. if lastPartSize != 241172480 {
  318. t.Fatalf("Error: expecting last part size of 241172480: got %v instead", lastPartSize)
  319. }
  320. totalPartsCount, partSize, lastPartSize, err = optimalPartInfo(5000000000)
  321. if err != nil {
  322. t.Fatal("Error:", err)
  323. }
  324. if partSize != minPartSize {
  325. t.Fatalf("Error: expecting part size of %v: got %v instead", minPartSize, partSize)
  326. }
  327. totalPartsCount, partSize, lastPartSize, err = optimalPartInfo(-1)
  328. if err != nil {
  329. t.Fatal("Error:", err)
  330. }
  331. if totalPartsCount != 9987 {
  332. t.Fatalf("Error: expecting total parts count of 9987: got %v instead", totalPartsCount)
  333. }
  334. if partSize != 550502400 {
  335. t.Fatalf("Error: expecting part size of 550502400: got %v instead", partSize)
  336. }
  337. if lastPartSize != 241172480 {
  338. t.Fatalf("Error: expecting last part size of 241172480: got %v instead", lastPartSize)
  339. }
  340. }