github.com/cloudwego/hertz@v0.9.3/pkg/common/stackless/writer_test.go (about) 1 /* 2 * Copyright 2022 CloudWeGo Authors 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 * The MIT License (MIT) 17 * 18 * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors 19 * 20 * Permission is hereby granted, free of charge, to any person obtaining a copy 21 * of this software and associated documentation files (the "Software"), to deal 22 * in the Software without restriction, including without limitation the rights 23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 * copies of the Software, and to permit persons to whom the Software is 25 * furnished to do so, subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be included in 28 * all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 * THE SOFTWARE. 37 * 38 * This file may have been modified by CloudWeGo authors. All CloudWeGo 39 * Modifications are Copyright 2022 CloudWeGo Authors. 40 */ 41 42 package stackless 43 44 import ( 45 "bytes" 46 "compress/flate" 47 "compress/gzip" 48 "fmt" 49 "io" 50 "io/ioutil" 51 "testing" 52 "time" 53 ) 54 55 func TestCompressFlateSerial(t *testing.T) { 56 if err := testCompressFlate(); err != nil { 57 t.Fatalf("unexpected error: %s", err) 58 } 59 } 60 61 func TestCompressFlateConcurrent(t *testing.T) { 62 if err := testConcurrent(testCompressFlate, 10); err != nil { 63 t.Fatalf("unexpected error: %s", err) 64 } 65 } 66 67 func testCompressFlate() error { 68 return testWriter(func(w io.Writer) Writer { 69 zw, err := flate.NewWriter(w, flate.DefaultCompression) 70 if err != nil { 71 panic(fmt.Sprintf("BUG: unexpected error: %s", err)) 72 } 73 return zw 74 }, func(r io.Reader) io.Reader { 75 return flate.NewReader(r) 76 }) 77 } 78 79 func TestCompressGzipSerial(t *testing.T) { 80 if err := testCompressGzip(); err != nil { 81 t.Fatalf("unexpected error: %s", err) 82 } 83 } 84 85 func TestCompressGzipConcurrent(t *testing.T) { 86 if err := testConcurrent(testCompressGzip, 10); err != nil { 87 t.Fatalf("unexpected error: %s", err) 88 } 89 } 90 91 func testCompressGzip() error { 92 return testWriter(func(w io.Writer) Writer { 93 return gzip.NewWriter(w) 94 }, func(r io.Reader) io.Reader { 95 zr, err := gzip.NewReader(r) 96 if err != nil { 97 panic(fmt.Sprintf("BUG: cannot create gzip reader: %s", err)) 98 } 99 return zr 100 }) 101 } 102 103 func testWriter(newWriter NewWriterFunc, newReader func(io.Reader) io.Reader) error { 104 dstW := &bytes.Buffer{} 105 w := NewWriter(dstW, newWriter) 106 107 for i := 0; i < 5; i++ { 108 if err := testWriterReuse(w, dstW, newReader); err != nil { 109 return fmt.Errorf("unexpected error when re-using writer on iteration %d: %s", i, err) 110 } 111 dstW = &bytes.Buffer{} 112 w.Reset(dstW) 113 } 114 115 return nil 116 } 117 118 func testWriterReuse(w Writer, r io.Reader, newReader func(io.Reader) io.Reader) error { 119 wantW := &bytes.Buffer{} 120 mw := io.MultiWriter(w, wantW) 121 for i := 0; i < 30; i++ { 122 fmt.Fprintf(mw, "foobar %d\n", i) 123 if i%13 == 0 { 124 if err := w.Flush(); err != nil { 125 return fmt.Errorf("error on flush: %s", err) 126 } 127 } 128 } 129 w.Close() 130 131 zr := newReader(r) 132 data, err := ioutil.ReadAll(zr) 133 if err != nil { 134 return fmt.Errorf("unexpected error: %s, data=%q", err, data) 135 } 136 137 wantData := wantW.Bytes() 138 if !bytes.Equal(data, wantData) { 139 return fmt.Errorf("unexpected data: %q. Expecting %q", data, wantData) 140 } 141 142 return nil 143 } 144 145 func testConcurrent(testFunc func() error, concurrency int) error { 146 ch := make(chan error, concurrency) 147 for i := 0; i < concurrency; i++ { 148 go func() { 149 ch <- testFunc() 150 }() 151 } 152 for i := 0; i < concurrency; i++ { 153 select { 154 case err := <-ch: 155 if err != nil { 156 return fmt.Errorf("unexpected error on goroutine %d: %s", i, err) 157 } 158 case <-time.After(time.Second): 159 return fmt.Errorf("timeout on goroutine %d", i) 160 } 161 } 162 return nil 163 }