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

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