github.com/keybase/client/go@v0.0.0-20240520164431-4f512a4c85a3/libkb/json_test.go (about)

     1  package libkb
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  type JSONTestFile struct {
    13  	*JSONFile
    14  }
    15  
    16  type JSONTestReader interface {
    17  	JSONReader
    18  }
    19  type JSONTestWriter interface {
    20  	JSONWriter
    21  }
    22  
    23  func TestJsonTransaction(t *testing.T) {
    24  	tc := SetupTest(t, "json", 1)
    25  	defer tc.Cleanup()
    26  
    27  	var wg sync.WaitGroup
    28  	for i := 0; i < 20; i++ {
    29  		wg.Add(1)
    30  		go func() {
    31  			tx, err := tc.G.Env.GetConfigWriter().BeginTransaction()
    32  			if err == nil {
    33  				_ = tx.Abort()
    34  			}
    35  			wg.Done()
    36  		}()
    37  	}
    38  	for i := 0; i < 20; i++ {
    39  		wg.Add(1)
    40  		go func() {
    41  			tx, err := tc.G.Env.GetConfigWriter().BeginTransaction()
    42  			if err == nil {
    43  				_ = tx.Commit()
    44  			}
    45  			wg.Done()
    46  		}()
    47  	}
    48  	wg.Wait()
    49  }
    50  
    51  func buildNewJSONFile(m MetaContext) (JSONTestReader, JSONTestWriter, *JSONTestFile) {
    52  	path := filepath.Join(m.G().Env.GetConfigDir(), "test-json-file")
    53  	jsonFile := JSONTestFile{NewJSONFile(m.G(), path, "test file from buildNewJSONFile")}
    54  	_ = jsonFile.Load(false)
    55  	return &jsonFile, &jsonFile, &jsonFile
    56  }
    57  
    58  func TestJsonSetAndGetString(t *testing.T) {
    59  	tc := SetupTest(t, "json", 1)
    60  	defer tc.Cleanup()
    61  	m := NewMetaContextForTest(tc)
    62  	reader, writer, rawFile := buildNewJSONFile(m)
    63  	defer func() { _ = rawFile.Nuke() }()
    64  
    65  	// verify that the path is empty first
    66  	path := "america.montana.bozeman"
    67  	value := "The American Computer Museum"
    68  	firstRead, isRet := reader.GetStringAtPath(path)
    69  	require.False(tc.T, isRet)
    70  	require.Equal(tc.T, firstRead, "")
    71  
    72  	// set, get, inspect
    73  	err := writer.SetStringAtPath(path, value)
    74  	require.NoError(tc.T, err)
    75  	secondRead, isRet := reader.GetStringAtPath(path)
    76  	require.True(tc.T, isRet)
    77  	require.Equal(tc.T, secondRead, value)
    78  }
    79  
    80  func TestJsonSetAndGetInt(t *testing.T) {
    81  	tc := SetupTest(t, "json", 1)
    82  	defer tc.Cleanup()
    83  	m := NewMetaContextForTest(tc)
    84  	reader, writer, rawFile := buildNewJSONFile(m)
    85  	defer func() { _ = rawFile.Nuke() }()
    86  
    87  	// verify that the path is empty first
    88  	path := "candy.skittles.count"
    89  	value := 12
    90  	firstRead, isRet := reader.GetIntAtPath(path)
    91  	require.False(tc.T, isRet)
    92  	require.Equal(tc.T, firstRead, 0)
    93  
    94  	// set, get, inspect
    95  	err := writer.SetIntAtPath(path, value)
    96  	require.NoError(tc.T, err)
    97  	secondRead, isRet := reader.GetIntAtPath(path)
    98  	require.True(tc.T, isRet)
    99  	require.Equal(tc.T, secondRead, value)
   100  }
   101  
   102  func TestJsonSetAndGetBool(t *testing.T) {
   103  	tc := SetupTest(t, "json", 1)
   104  	defer tc.Cleanup()
   105  	m := NewMetaContextForTest(tc)
   106  	reader, writer, rawFile := buildNewJSONFile(m)
   107  	defer func() { _ = rawFile.Nuke() }()
   108  
   109  	// verify that the path is empty first
   110  	path := "colors.orange.appetizing"
   111  	value := true
   112  	firstRead, isRet := reader.GetBoolAtPath(path)
   113  	require.False(tc.T, isRet)
   114  	require.Equal(tc.T, firstRead, false)
   115  
   116  	// set, get, inspect
   117  	err := writer.SetBoolAtPath(path, value)
   118  	require.NoError(tc.T, err)
   119  	secondRead, isRet := reader.GetBoolAtPath(path)
   120  	require.True(tc.T, isRet)
   121  	require.True(tc.T, secondRead)
   122  }
   123  
   124  func TestJsonSetAndGetNull(t *testing.T) {
   125  	tc := SetupTest(t, "json", 1)
   126  	defer tc.Cleanup()
   127  	m := NewMetaContextForTest(tc)
   128  	reader, writer, rawFile := buildNewJSONFile(m)
   129  	defer func() { _ = rawFile.Nuke() }()
   130  
   131  	// verify that the path is empty first
   132  	// and that GetNull knows the path wasn't set
   133  	path := "worldcup.victories.croatia"
   134  	value := 2018
   135  	isRet := reader.GetNullAtPath(path)
   136  	require.False(tc.T, isRet)
   137  
   138  	// set, get, inspect
   139  	_ = writer.SetIntAtPath(path, value)
   140  	secondRead, _ := reader.GetIntAtPath(path)
   141  	require.Equal(tc.T, secondRead, value)
   142  	// null it out and verify
   143  	err := writer.SetNullAtPath(path)
   144  	require.NoError(tc.T, err)
   145  	isRet = reader.GetNullAtPath(path)
   146  	require.True(tc.T, isRet)
   147  }
   148  
   149  func TestJsonTxRollback(t *testing.T) {
   150  	tc := SetupTest(t, "json", 1)
   151  	defer tc.Cleanup()
   152  	m := NewMetaContextForTest(tc)
   153  	G := m.G()
   154  
   155  	// Make a tx, write something, then commit. Expecting to be able
   156  	// to read that back during the transaction and after commit.
   157  	w := G.Env.GetConfigWriter()
   158  	tx, err := w.BeginTransaction()
   159  	require.NoError(t, err)
   160  	require.NoError(t, w.SetStringAtPath("bbbbar", "world, over?"))
   161  	i, err := G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
   162  	require.NoError(t, err)
   163  	require.Equal(t, "world, over?", i)
   164  	require.NoError(t, tx.Commit())
   165  	i, err = G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
   166  	require.NoError(t, err)
   167  	require.Equal(t, "world, over?", i)
   168  
   169  	// Make a tx, write something, then Rollback and Abort. It should
   170  	// be as the write never happened.
   171  	w = G.Env.GetConfigWriter()
   172  	tx, err = w.BeginTransaction()
   173  	require.NoError(t, err)
   174  	require.NoError(t, w.SetStringAtPath("fooozzzz", "hello World"))
   175  	i, err = G.Env.GetConfig().GetInterfaceAtPath("fooozzzz")
   176  	require.NoError(t, err)
   177  	require.Equal(t, "hello World", i)
   178  	require.NoError(t, tx.Rollback())
   179  	require.NoError(t, tx.Abort())
   180  	_, err = G.Env.GetConfig().GetInterfaceAtPath("fooozzzz")
   181  	require.Error(t, err)
   182  	require.Contains(t, err.Error(), "no such key")
   183  	i, err = G.Env.GetConfig().GetInterfaceAtPath("bbbbar")
   184  	require.NoError(t, err)
   185  	require.Equal(t, "world, over?", i)
   186  }
   187  
   188  func TestJsonNonExistingFileRollback(t *testing.T) {
   189  	tc := SetupTest(t, "json", 1)
   190  	defer tc.Cleanup()
   191  	m := NewMetaContextForTest(tc)
   192  	reader, writer, rawFile := buildNewJSONFile(m)
   193  	defer func() { _ = rawFile.Nuke() }()
   194  
   195  	tx, err := rawFile.BeginTransaction()
   196  	require.NoError(t, err)
   197  	require.NoError(t, writer.SetStringAtPath("test1", "this is value 1"))
   198  	require.NoError(t, writer.SetIntAtPath("test two", 2))
   199  
   200  	i, err := reader.GetInterfaceAtPath("test1")
   201  	require.NoError(t, err)
   202  	require.Equal(t, "this is value 1", i)
   203  
   204  	i, err = reader.GetInterfaceAtPath("test two")
   205  	require.NoError(t, err)
   206  	require.Equal(t, 2, i)
   207  
   208  	require.NoError(t, tx.Rollback())
   209  	require.NoError(t, tx.Abort())
   210  
   211  	_, err = os.Stat(rawFile.filename)
   212  	require.Error(t, err)
   213  	require.True(t, os.IsNotExist(err))
   214  
   215  	_, err = reader.GetInterfaceAtPath("test1")
   216  	require.Error(t, err)
   217  	require.Contains(t, err.Error(), "no such key")
   218  
   219  	_, err = reader.GetInterfaceAtPath("test two")
   220  	require.Error(t, err)
   221  	require.Contains(t, err.Error(), "no such key")
   222  }