github.com/qiniu/go-sdk/v7@v7.27.0/internal/clientv2/multipart_test.go (about)

     1  //go:build unit
     2  // +build unit
     3  
     4  package clientv2
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/md5"
     9  	"io"
    10  	"math/rand"
    11  	"mime"
    12  	"mime/multipart"
    13  	"net/http"
    14  	"os"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  func TestMultipart(t *testing.T) {
    20  	file1 := randFile(t, 1024*1024*10)
    21  	defer file1.Close()
    22  	file2 := randFile(t, 1024*1024*10)
    23  	defer file2.Close()
    24  
    25  	form := new(MultipartForm).
    26  		SetValue("test-1", "value-1").
    27  		SetValue("test-2", "value-2").
    28  		SetFile("test-file-1", "test-file-name-1", "application/json", file1).
    29  		SetFile("test-file-2", "test-file-name-2", "application/x-www-form-urlencoded", file2)
    30  	getRequestBody := GetMultipartFormRequestBody(form)
    31  
    32  	for i := 0; i < 5; i++ {
    33  		header := make(http.Header)
    34  		requestBody, err := getRequestBody(&RequestParams{Header: header})
    35  		if err != nil {
    36  			t.Fatal(err)
    37  		}
    38  		reader, err := parseMultipart(requestBody, header)
    39  		if err != nil {
    40  			t.Fatal(err)
    41  		}
    42  		if part, err := reader.NextPart(); err != nil {
    43  			t.Fatal(err)
    44  		} else {
    45  			assertPartValue(t, part, "test-1", "value-1")
    46  		}
    47  		if part, err := reader.NextPart(); err != nil {
    48  			t.Fatal(err)
    49  		} else {
    50  			assertPartValue(t, part, "test-2", "value-2")
    51  		}
    52  		if part, err := reader.NextPart(); err != nil {
    53  			t.Fatal(err)
    54  		} else if f, err := os.Open(file1.Name()); err != nil {
    55  			t.Fatal(err)
    56  		} else {
    57  			assertPartFile(t, part, "test-file-1", "test-file-name-1", "application/json", f)
    58  			f.Close()
    59  		}
    60  		if part, err := reader.NextPart(); err != nil {
    61  			t.Fatal(err)
    62  		} else if f, err := os.Open(file2.Name()); err != nil {
    63  			t.Fatal(err)
    64  		} else {
    65  			assertPartFile(t, part, "test-file-2", "test-file-name-2", "application/x-www-form-urlencoded", f)
    66  			f.Close()
    67  		}
    68  		if _, err = reader.NextPart(); err != io.EOF {
    69  			t.Fatalf("unexpected error: %v", err)
    70  		}
    71  	}
    72  }
    73  
    74  func randFile(t *testing.T, n int64) *os.File {
    75  	file, err := os.CreateTemp("", "")
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	_, err = io.CopyN(file, rand.New(rand.NewSource(time.Now().UnixNano())), 1024*1024*10)
    80  	if err != nil {
    81  		t.Fatal(err)
    82  	}
    83  	_, err = file.Seek(0, io.SeekStart)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	return file
    88  }
    89  
    90  func parseMultipart(r io.Reader, header http.Header) (*multipart.Reader, error) {
    91  	_, params, err := mime.ParseMediaType(header.Get("Content-Type"))
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	return multipart.NewReader(r, params["boundary"]), nil
    96  }
    97  
    98  func assertPartValue(t *testing.T, part *multipart.Part, key, value string) {
    99  	if part.FormName() != key {
   100  		t.Fatalf("unexpected form name: %s != %s", part.FormName(), key)
   101  	}
   102  	buf := new(bytes.Buffer)
   103  	if _, err := io.Copy(buf, part); err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	if buf.String() != value {
   107  		t.Fatalf("unexpected form value: %s != %s", buf.String(), value)
   108  	}
   109  }
   110  
   111  func assertPartFile(t *testing.T, part *multipart.Part, key, fileName, contentType string, value io.Reader) {
   112  	if part.FormName() != key {
   113  		t.Fatalf("unexpected form name: %s != %s", part.FormName(), key)
   114  	}
   115  	if part.FileName() != fileName {
   116  		t.Fatalf("unexpected file name: %s != %s", part.FileName(), fileName)
   117  	}
   118  	if acutalContentType := part.Header.Get("Content-Type"); acutalContentType != contentType {
   119  		t.Fatalf("unexpected content type: %s != %s", acutalContentType, contentType)
   120  	}
   121  	md5Hasher := md5.New()
   122  	if _, err := io.Copy(md5Hasher, part); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	actualMd5 := md5Hasher.Sum(nil)
   126  	md5Hasher.Reset()
   127  	if _, err := io.Copy(md5Hasher, value); err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	expectedMd5 := md5Hasher.Sum(nil)
   131  	if !bytes.Equal(actualMd5, expectedMd5) {
   132  		t.Fatalf("unexpected form file value")
   133  	}
   134  }