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  }