hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

init_test.go (4456B)

    1 // Copyright 2019 The Hugo Authors. All rights reserved.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 // http://www.apache.org/licenses/LICENSE-2.0
    7 //
    8 // Unless required by applicable law or agreed to in writing, software
    9 // distributed under the License is distributed on an "AS IS" BASIS,
   10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   11 // See the License for the specific language governing permissions and
   12 // limitations under the License.
   13 
   14 package lazy
   15 
   16 import (
   17 	"context"
   18 	"errors"
   19 	"math/rand"
   20 	"strings"
   21 	"sync"
   22 	"testing"
   23 	"time"
   24 
   25 	qt "github.com/frankban/quicktest"
   26 )
   27 
   28 var (
   29 	rnd        = rand.New(rand.NewSource(time.Now().UnixNano()))
   30 	bigOrSmall = func() int {
   31 		if rnd.Intn(10) < 5 {
   32 			return 10000 + rnd.Intn(100000)
   33 		}
   34 		return 1 + rnd.Intn(50)
   35 	}
   36 )
   37 
   38 func doWork() {
   39 	doWorkOfSize(bigOrSmall())
   40 }
   41 
   42 func doWorkOfSize(size int) {
   43 	_ = strings.Repeat("Hugo Rocks! ", size)
   44 }
   45 
   46 func TestInit(t *testing.T) {
   47 	c := qt.New(t)
   48 
   49 	var result string
   50 
   51 	f1 := func(name string) func() (any, error) {
   52 		return func() (any, error) {
   53 			result += name + "|"
   54 			doWork()
   55 			return name, nil
   56 		}
   57 	}
   58 
   59 	f2 := func() func() (any, error) {
   60 		return func() (any, error) {
   61 			doWork()
   62 			return nil, nil
   63 		}
   64 	}
   65 
   66 	root := New()
   67 
   68 	root.Add(f1("root(1)"))
   69 	root.Add(f1("root(2)"))
   70 
   71 	branch1 := root.Branch(f1("branch_1"))
   72 	branch1.Add(f1("branch_1_1"))
   73 	branch1_2 := branch1.Add(f1("branch_1_2"))
   74 	branch1_2_1 := branch1_2.Add(f1("branch_1_2_1"))
   75 
   76 	var wg sync.WaitGroup
   77 
   78 	// Add some concurrency and randomness to verify thread safety and
   79 	// init order.
   80 	for i := 0; i < 100; i++ {
   81 		wg.Add(1)
   82 		go func(i int) {
   83 			defer wg.Done()
   84 			var err error
   85 			if rnd.Intn(10) < 5 {
   86 				_, err = root.Do()
   87 				c.Assert(err, qt.IsNil)
   88 			}
   89 
   90 			// Add a new branch on the fly.
   91 			if rnd.Intn(10) > 5 {
   92 				branch := branch1_2.Branch(f2())
   93 				_, err = branch.Do()
   94 				c.Assert(err, qt.IsNil)
   95 			} else {
   96 				_, err = branch1_2_1.Do()
   97 				c.Assert(err, qt.IsNil)
   98 			}
   99 			_, err = branch1_2.Do()
  100 			c.Assert(err, qt.IsNil)
  101 		}(i)
  102 
  103 		wg.Wait()
  104 
  105 		c.Assert(result, qt.Equals, "root(1)|root(2)|branch_1|branch_1_1|branch_1_2|branch_1_2_1|")
  106 
  107 	}
  108 }
  109 
  110 func TestInitAddWithTimeout(t *testing.T) {
  111 	c := qt.New(t)
  112 
  113 	init := New().AddWithTimeout(100*time.Millisecond, func(ctx context.Context) (any, error) {
  114 		return nil, nil
  115 	})
  116 
  117 	_, err := init.Do()
  118 
  119 	c.Assert(err, qt.IsNil)
  120 }
  121 
  122 func TestInitAddWithTimeoutTimeout(t *testing.T) {
  123 	c := qt.New(t)
  124 
  125 	init := New().AddWithTimeout(100*time.Millisecond, func(ctx context.Context) (any, error) {
  126 		time.Sleep(500 * time.Millisecond)
  127 		select {
  128 		case <-ctx.Done():
  129 			return nil, nil
  130 		default:
  131 		}
  132 		t.Fatal("slept")
  133 		return nil, nil
  134 	})
  135 
  136 	_, err := init.Do()
  137 
  138 	c.Assert(err, qt.Not(qt.IsNil))
  139 
  140 	c.Assert(err.Error(), qt.Contains, "timed out")
  141 
  142 	time.Sleep(1 * time.Second)
  143 }
  144 
  145 func TestInitAddWithTimeoutError(t *testing.T) {
  146 	c := qt.New(t)
  147 
  148 	init := New().AddWithTimeout(100*time.Millisecond, func(ctx context.Context) (any, error) {
  149 		return nil, errors.New("failed")
  150 	})
  151 
  152 	_, err := init.Do()
  153 
  154 	c.Assert(err, qt.Not(qt.IsNil))
  155 }
  156 
  157 type T struct {
  158 	sync.Mutex
  159 	V1 string
  160 	V2 string
  161 }
  162 
  163 func (t *T) Add1(v string) {
  164 	t.Lock()
  165 	t.V1 += v
  166 	t.Unlock()
  167 }
  168 
  169 func (t *T) Add2(v string) {
  170 	t.Lock()
  171 	t.V2 += v
  172 	t.Unlock()
  173 }
  174 
  175 // https://github.com/gohugoio/hugo/issues/5901
  176 func TestInitBranchOrder(t *testing.T) {
  177 	c := qt.New(t)
  178 
  179 	base := New()
  180 
  181 	work := func(size int, f func()) func() (any, error) {
  182 		return func() (any, error) {
  183 			doWorkOfSize(size)
  184 			if f != nil {
  185 				f()
  186 			}
  187 
  188 			return nil, nil
  189 		}
  190 	}
  191 
  192 	state := &T{}
  193 
  194 	base = base.Add(work(10000, func() {
  195 		state.Add1("A")
  196 	}))
  197 
  198 	inits := make([]*Init, 2)
  199 	for i := range inits {
  200 		inits[i] = base.Branch(work(i+1*100, func() {
  201 			// V1 is A
  202 			ab := state.V1 + "B"
  203 			state.Add2(ab)
  204 		}))
  205 	}
  206 
  207 	var wg sync.WaitGroup
  208 
  209 	for _, v := range inits {
  210 		v := v
  211 		wg.Add(1)
  212 		go func() {
  213 			defer wg.Done()
  214 			_, err := v.Do()
  215 			c.Assert(err, qt.IsNil)
  216 		}()
  217 	}
  218 
  219 	wg.Wait()
  220 
  221 	c.Assert(state.V2, qt.Equals, "ABAB")
  222 }
  223 
  224 // See issue 7043
  225 func TestResetError(t *testing.T) {
  226 	c := qt.New(t)
  227 	r := false
  228 	i := New().Add(func() (any, error) {
  229 		if r {
  230 			return nil, nil
  231 		}
  232 		return nil, errors.New("r is false")
  233 	})
  234 	_, err := i.Do()
  235 	c.Assert(err, qt.IsNotNil)
  236 	i.Reset()
  237 	r = true
  238 	_, err = i.Do()
  239 	c.Assert(err, qt.IsNil)
  240 
  241 }