lab.nexedi.com/kirr/go123@v0.0.0-20240207185015-8299741fa871/xnet/lonet/registry_sqlite_test.go (about)

     1  // Copyright (C) 2018  Nexedi SA and Contributors.
     2  //                     Kirill Smelkov <kirr@nexedi.com>
     3  //
     4  // This program is free software: you can Use, Study, Modify and Redistribute
     5  // it under the terms of the GNU General Public License version 3, or (at your
     6  // option) any later version, as published by the Free Software Foundation.
     7  //
     8  // You can also Link and Combine this program with other software covered by
     9  // the terms of any of the Free Software licenses or any of the Open Source
    10  // Initiative approved licenses and Convey the resulting work. Corresponding
    11  // source of such a combination shall include the source code for all other
    12  // software used.
    13  //
    14  // This program is distributed WITHOUT ANY WARRANTY; without even the implied
    15  // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    16  //
    17  // See COPYING file for full licensing terms.
    18  // See https://www.nexedi.com/licensing for rationale and options.
    19  
    20  package lonet
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  	"testing"
    26  
    27  	"lab.nexedi.com/kirr/go123/exc"
    28  	"lab.nexedi.com/kirr/go123/xnet/virtnet"
    29  )
    30  
    31  // registryTester is handy utility to test sqliteRegistry
    32  type registryTester struct {
    33  	*testing.T
    34  	r *sqliteRegistry
    35  }
    36  
    37  // Query checks that result of Query(hostname) is as expected.
    38  //
    39  // if expect is error - it checks that Query returns error with cause == expect.
    40  // otherwise expect must be string and it will check that Query
    41  // succeeds and returns osladdr == expect.
    42  func (t *registryTester) Query(hostname string, expect interface{}) {
    43  	t.Helper()
    44  	r := t.r
    45  
    46  	osladdr, err := r.Query(context.Background(), hostname)
    47  	if ewant, iserr := expect.(error); iserr {
    48  		// error expected
    49  		// XXX construct full registry error around ewant + reflect.DeepCompare?
    50  		e, ok := err.(*virtnet.RegistryError)
    51  		if !(ok && e.Err == ewant && osladdr == "") {
    52  			t.Fatalf("%s: query %q:\nwant: \"\", %v\nhave: %q, %v",
    53  				r.uri, hostname, ewant, osladdr, err)
    54  		}
    55  	} else {
    56  		// !error expected
    57  		laddr := expect.(string)
    58  		if !(osladdr == laddr && err == nil) {
    59  			t.Fatalf("%s: query %q:\nwant: %q, nil\nhave: %q, %v",
    60  				r.uri, hostname, laddr, osladdr, err)
    61  		}
    62  	}
    63  }
    64  
    65  // Announce checks that result of Announce(hostname, osladdr) is as expected.
    66  //
    67  // if len(errv) == 1 - it checks that Announce returns error with cause == errv[0].
    68  // otherwise it will check that Announce succeeds and returns nil error.
    69  func (t *registryTester) Announce(hostname, osladdr string, errv ...error) {
    70  	t.Helper()
    71  	r := t.r
    72  
    73  	err := r.Announce(context.Background(), hostname, osladdr)
    74  	var ewant error
    75  	if len(errv) > 0 {
    76  		ewant = errv[0]
    77  		if len(errv) > 1 {
    78  			panic("only 1 error allowed in announce check")
    79  		}
    80  	}
    81  	if ewant != nil {
    82  		// error expected
    83  		// XXX construct full registry error around ewant + reflect.DeepCompare?
    84  		e, ok := err.(*virtnet.RegistryError)
    85  		if (!ok && e.Err == ewant) {
    86  			t.Fatalf("%s: announce %q %q:\nwant %v\nhave: %v",
    87  				r.uri, hostname, osladdr, ewant, err)
    88  		}
    89  	} else {
    90  		// !error expected
    91  		if err != nil {
    92  			t.Fatalf("%s: announce %q %q: %s", r.uri, hostname, osladdr, err)
    93  		}
    94  	}
    95  }
    96  
    97  // handy shortcuts for registry errors, ...
    98  var ø     = virtnet.ErrNoHost
    99  var DUP   = virtnet.ErrHostDup
   100  var RDOWN = virtnet.ErrRegistryDown
   101  
   102  var X  = exc.Raiseif
   103  var bg = context.Background()
   104  
   105  
   106  func TestRegistrySQLite(t *testing.T) {
   107  	work := xworkdir(t)
   108  	dbpath := work + "/1.db"
   109  
   110  	r1, err := openRegistrySQLite(bg, dbpath, "aaa")
   111  	X(err)
   112  
   113  	t1 := &registryTester{t, r1}
   114  	t1.Query("α", ø)
   115  	t1.Announce("α", "alpha:1234")
   116  	t1.Announce("α", "alpha:1234", DUP)
   117  	t1.Announce("α", "alpha:1235", DUP)
   118  	t1.Query("α", "alpha:1234")
   119  	t1.Query("β", ø)
   120  
   121  	r2, err := openRegistrySQLite(bg, dbpath, "aaa")
   122  	X(err)
   123  
   124  	t2 := &registryTester{t, r2}
   125  	t2.Query("α", "alpha:1234")
   126  	t2.Query("β", ø)
   127  	t2.Announce("β", "beta:zzz")
   128  	t2.Query("β", "beta:zzz")
   129  
   130  	t1.Query("β", "beta:zzz")
   131  
   132  	X(r1.Close())
   133  
   134  	t1.Query("α", RDOWN)
   135  	t1.Query("β", RDOWN)
   136  	t1.Announce("γ", "gamma:qqq", RDOWN)
   137  	t1.Query("γ", RDOWN)
   138  
   139  	t2.Query("α", "alpha:1234")
   140  
   141  	X(r2.Close())
   142  
   143  	t2.Query("α", RDOWN)
   144  
   145  
   146  	// verify network mismatch detection works
   147  	r3, err := openRegistrySQLite(bg, dbpath, "bbb")
   148  	if !(r3 == nil && err != nil) {
   149  		t.Fatalf("network mismatch: not detected")
   150  	}
   151  	errWant := fmt.Sprintf(`%s: open []: setup "bbb": network name mismatch: want "bbb"; have "aaa"`, dbpath)
   152  	if err.Error() != errWant {
   153  		t.Fatalf("network mismatch: error:\nhave: %q\nwant: %q", err.Error(), errWant)
   154  	}
   155  }
   156  
   157  
   158  // verify that go and python implementations of sqlite registry understand each other.
   159  func TestRegistrySQLitePyGo(t *testing.T) {
   160  	needPy(t)
   161  
   162  	work := xworkdir(t)
   163  	dbpath := work + "/1.db"
   164  
   165  	r1, err := openRegistrySQLite(bg, dbpath, "ccc")
   166  	X(err)
   167  
   168  	t1 := &registryTester{t, r1}
   169  	t1.Query("α", ø)
   170  	t1.Announce("α", "alpha:1234")
   171  	t1.Announce("α", "alpha:1234", DUP)
   172  	t1.Announce("α", "alpha:1235", DUP)
   173  	t1.Query("α", "alpha:1234")
   174  	t1.Query("β", ø)
   175  
   176  	// in python: check/modify the registry
   177  	err = pytest("-k", "test_registry_pygo", "--registry-dbpath", dbpath, "lonet_test.py")
   178  	X(err)
   179  
   180  	// back in go: python must have set β + α should stay the same
   181  	t1.Query("β", "beta:py")
   182  	t1.Query("α", "alpha:1234")
   183  }