go.mercari.io/datastore@v1.8.2/testsuite/dsmiddleware/fishbone/fishbone.go (about)

     1  package fishbone
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/MakeNowJust/heredoc/v2"
    10  	"go.mercari.io/datastore"
    11  	"go.mercari.io/datastore/dsmiddleware/dslog"
    12  	"go.mercari.io/datastore/dsmiddleware/fishbone"
    13  	"go.mercari.io/datastore/testsuite"
    14  	"google.golang.org/api/iterator"
    15  )
    16  
    17  // TestSuite contains all the test cases that this package provides.
    18  var TestSuite = map[string]testsuite.Test{
    19  	"FishBone_QueryWithoutTx": queryWithoutTx,
    20  	"FishBone_QueryWithTx":    queryWithTx,
    21  }
    22  
    23  func init() {
    24  	testsuite.MergeTestSuite(TestSuite)
    25  }
    26  
    27  func queryWithoutTx(ctx context.Context, t *testing.T, client datastore.Client) {
    28  	defer func() {
    29  		err := client.Close()
    30  		if err != nil {
    31  			t.Fatal(err)
    32  		}
    33  	}()
    34  
    35  	var logs []string
    36  	logf := func(ctx context.Context, format string, args ...interface{}) {
    37  		t.Logf(format, args...)
    38  		logs = append(logs, fmt.Sprintf(format, args...))
    39  	}
    40  
    41  	// setup. strategies are first in - first apply.
    42  
    43  	bLog := dslog.NewLogger("before: ", logf)
    44  	client.AppendMiddleware(bLog)
    45  	defer func() {
    46  		// stop logging before cleanUp func called.
    47  		client.RemoveMiddleware(bLog)
    48  	}()
    49  
    50  	m := fishbone.New()
    51  	client.AppendMiddleware(m)
    52  	defer func() {
    53  		// stop logging before cleanUp func called.
    54  		client.RemoveMiddleware(m)
    55  	}()
    56  
    57  	aLog := dslog.NewLogger("after: ", logf)
    58  	client.AppendMiddleware(aLog)
    59  	defer func() {
    60  		// stop logging before cleanUp func called.
    61  		client.RemoveMiddleware(aLog)
    62  	}()
    63  
    64  	// exec.
    65  
    66  	type Data struct {
    67  		Name string
    68  	}
    69  
    70  	const size = 3
    71  
    72  	keys := make([]datastore.Key, size)
    73  	list := make([]*Data, size)
    74  	for i := 0; i < size; i++ {
    75  		keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), nil)
    76  		list[i] = &Data{
    77  			Name: fmt.Sprintf("#%d", i+1),
    78  		}
    79  	}
    80  	_, err := client.PutMulti(ctx, keys, list)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	q := client.NewQuery("Data").Order("-Name")
    86  
    87  	// Run
    88  	iter := client.Run(ctx, q)
    89  
    90  	// Next
    91  	cnt := 0
    92  	for {
    93  		obj := &Data{}
    94  		key, err := iter.Next(obj)
    95  		if err == iterator.Done {
    96  			break
    97  		} else if err != nil {
    98  			t.Fatal(err)
    99  		}
   100  		if v := obj.Name; v == "" || v != key.Name() {
   101  			t.Errorf("unexpected: %v", cnt)
   102  		}
   103  		cnt++
   104  	}
   105  	if cnt != size {
   106  		t.Errorf("unexpected: %v", cnt)
   107  	}
   108  
   109  	// GetAll
   110  	q = client.NewQuery("Data").Order("-Name")
   111  	list = nil
   112  	keys, err = client.GetAll(ctx, q, &list)
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	if v := len(list); v != size {
   117  		t.Errorf("unexpected: %v", v)
   118  	}
   119  	for idx, obj := range list {
   120  		if v := obj.Name; v == "" || v != keys[idx].Name() {
   121  			t.Errorf("unexpected: %v", v)
   122  		}
   123  	}
   124  
   125  	expected := heredoc.Doc(`
   126  		before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3]
   127  		after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3]
   128  		after: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3]
   129  		before: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3]
   130  		before: Run #2, q=v1:Data&or=-Name
   131  		after: Run #2, q=v1:Data&or=-Name&k=t
   132  		before: Next #3, q=v1:Data&or=-Name
   133  		after: Next #3, q=v1:Data&or=-Name
   134  		after: Next #3, key=/Data,#3
   135  		before: GetMultiWithoutTx #4, len(keys)=1, keys=[/Data,#3]
   136  		after: GetMultiWithoutTx #4, len(keys)=1, keys=[/Data,#3]
   137  		before: Next #3, key=/Data,#3
   138  		before: Next #5, q=v1:Data&or=-Name
   139  		after: Next #5, q=v1:Data&or=-Name
   140  		after: Next #5, key=/Data,#2
   141  		before: GetMultiWithoutTx #6, len(keys)=1, keys=[/Data,#2]
   142  		after: GetMultiWithoutTx #6, len(keys)=1, keys=[/Data,#2]
   143  		before: Next #5, key=/Data,#2
   144  		before: Next #7, q=v1:Data&or=-Name
   145  		after: Next #7, q=v1:Data&or=-Name
   146  		after: Next #7, key=/Data,#1
   147  		before: GetMultiWithoutTx #8, len(keys)=1, keys=[/Data,#1]
   148  		after: GetMultiWithoutTx #8, len(keys)=1, keys=[/Data,#1]
   149  		before: Next #7, key=/Data,#1
   150  		before: Next #9, q=v1:Data&or=-Name
   151  		after: Next #9, q=v1:Data&or=-Name
   152  		after: Next #9, err=no more items in iterator
   153  		before: Next #9, err=no more items in iterator
   154  		before: GetAll #10, q=v1:Data&or=-Name
   155  		after: GetAll #10, q=v1:Data&or=-Name&k=t
   156  		after: GetAll #10, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1]
   157  		before: GetMultiWithoutTx #11, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1]
   158  		after: GetMultiWithoutTx #11, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1]
   159  		before: GetAll #10, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1]
   160  	`)
   161  
   162  	if v := strings.Join(logs, "\n") + "\n"; v != expected {
   163  		t.Errorf("unexpected: %v", v)
   164  	}
   165  }
   166  
   167  func queryWithTx(ctx context.Context, t *testing.T, client datastore.Client) {
   168  	defer func() {
   169  		err := client.Close()
   170  		if err != nil {
   171  			t.Fatal(err)
   172  		}
   173  	}()
   174  
   175  	var logs []string
   176  	logf := func(ctx context.Context, format string, args ...interface{}) {
   177  		t.Logf(format, args...)
   178  		logs = append(logs, fmt.Sprintf(format, args...))
   179  	}
   180  
   181  	// setup. strategies are first in - first apply.
   182  
   183  	bLog := dslog.NewLogger("before: ", logf)
   184  	client.AppendMiddleware(bLog)
   185  	defer func() {
   186  		// stop logging before cleanUp func called.
   187  		client.RemoveMiddleware(bLog)
   188  	}()
   189  
   190  	m := fishbone.New()
   191  	client.AppendMiddleware(m)
   192  	defer func() {
   193  		// stop logging before cleanUp func called.
   194  		client.RemoveMiddleware(m)
   195  	}()
   196  
   197  	aLog := dslog.NewLogger("after: ", logf)
   198  	client.AppendMiddleware(aLog)
   199  	defer func() {
   200  		// stop logging before cleanUp func called.
   201  		client.RemoveMiddleware(aLog)
   202  	}()
   203  
   204  	// exec.
   205  
   206  	type Data struct {
   207  		Name string
   208  	}
   209  
   210  	const size = 3
   211  
   212  	parentKey := client.NameKey("Parent", "p", nil)
   213  	keys := make([]datastore.Key, size)
   214  	list := make([]*Data, size)
   215  	for i := 0; i < size; i++ {
   216  		keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), parentKey)
   217  		list[i] = &Data{
   218  			Name: fmt.Sprintf("#%d", i+1),
   219  		}
   220  	}
   221  	_, err := client.PutMulti(ctx, keys, list)
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	tx, err := client.NewTransaction(ctx)
   227  	if err != nil {
   228  		t.Fatal(err)
   229  	}
   230  	defer func() {
   231  		err := tx.Rollback()
   232  		if err != nil {
   233  			t.Fatal(err)
   234  		}
   235  	}()
   236  
   237  	q := client.NewQuery("Data").Order("-Name").Ancestor(parentKey).Transaction(tx)
   238  
   239  	// Run
   240  	iter := client.Run(ctx, q)
   241  
   242  	// Next
   243  	cnt := 0
   244  	for {
   245  		obj := &Data{}
   246  		key, err := iter.Next(obj)
   247  		if err == iterator.Done {
   248  			break
   249  		} else if err != nil {
   250  			t.Fatal(err)
   251  		}
   252  		if v := obj.Name; v == "" || v != key.Name() {
   253  			t.Errorf("unexpected: %v", cnt)
   254  		}
   255  		cnt++
   256  	}
   257  	if cnt != size {
   258  		t.Errorf("unexpected: %v", cnt)
   259  	}
   260  
   261  	// GetAll
   262  	q = client.NewQuery("Data").Order("-Name").Ancestor(parentKey).Transaction(tx)
   263  	list = nil
   264  	keys, err = client.GetAll(ctx, q, &list)
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  	if v := len(list); v != size {
   269  		t.Errorf("unexpected: %v", v)
   270  	}
   271  	for idx, obj := range list {
   272  		if v := obj.Name; v == "" || v != keys[idx].Name() {
   273  			t.Errorf("unexpected: %v", v)
   274  		}
   275  	}
   276  
   277  	expected := heredoc.Doc(`
   278  		before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3]
   279  		after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3]
   280  		after: PutMultiWithoutTx #1, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3]
   281  		before: PutMultiWithoutTx #1, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3]
   282  		before: Run #2, q=v1:Data&a=/Parent,p&t=t&or=-Name
   283  		after: Run #2, q=v1:Data&a=/Parent,p&t=t&or=-Name&k=t
   284  		before: Next #3, q=v1:Data&a=/Parent,p&t=t&or=-Name
   285  		after: Next #3, q=v1:Data&a=/Parent,p&t=t&or=-Name
   286  		after: Next #3, key=/Parent,p/Data,#3
   287  		before: GetMultiWithTx #4, len(keys)=1, keys=[/Parent,p/Data,#3]
   288  		after: GetMultiWithTx #4, len(keys)=1, keys=[/Parent,p/Data,#3]
   289  		before: Next #3, key=/Parent,p/Data,#3
   290  		before: Next #5, q=v1:Data&a=/Parent,p&t=t&or=-Name
   291  		after: Next #5, q=v1:Data&a=/Parent,p&t=t&or=-Name
   292  		after: Next #5, key=/Parent,p/Data,#2
   293  		before: GetMultiWithTx #6, len(keys)=1, keys=[/Parent,p/Data,#2]
   294  		after: GetMultiWithTx #6, len(keys)=1, keys=[/Parent,p/Data,#2]
   295  		before: Next #5, key=/Parent,p/Data,#2
   296  		before: Next #7, q=v1:Data&a=/Parent,p&t=t&or=-Name
   297  		after: Next #7, q=v1:Data&a=/Parent,p&t=t&or=-Name
   298  		after: Next #7, key=/Parent,p/Data,#1
   299  		before: GetMultiWithTx #8, len(keys)=1, keys=[/Parent,p/Data,#1]
   300  		after: GetMultiWithTx #8, len(keys)=1, keys=[/Parent,p/Data,#1]
   301  		before: Next #7, key=/Parent,p/Data,#1
   302  		before: Next #9, q=v1:Data&a=/Parent,p&t=t&or=-Name
   303  		after: Next #9, q=v1:Data&a=/Parent,p&t=t&or=-Name
   304  		after: Next #9, err=no more items in iterator
   305  		before: Next #9, err=no more items in iterator
   306  		before: GetAll #10, q=v1:Data&a=/Parent,p&t=t&or=-Name
   307  		after: GetAll #10, q=v1:Data&a=/Parent,p&t=t&or=-Name&k=t
   308  		after: GetAll #10, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1]
   309  		before: GetMultiWithTx #11, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1]
   310  		after: GetMultiWithTx #11, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1]
   311  		before: GetAll #10, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1]
   312  	`)
   313  
   314  	if v := strings.Join(logs, "\n") + "\n"; v != expected {
   315  		t.Errorf("unexpected: %v", v)
   316  	}
   317  }