func TestGetFirstRangeDescriptor(t *testing.T) { n := gossip.NewSimulationNetwork(3, "unix", gossip.DefaultTestGossipInterval) kv := NewDistKV(n.Nodes[0].Gossip) if _, err := kv.getFirstRangeDescriptor(); err == nil { t.Errorf("expected not to find first range descriptor") } expectedDesc := &proto.RangeDescriptor{} expectedDesc.StartKey = engine.Key("a") expectedDesc.EndKey = engine.Key("c") // Add first RangeDescriptor to a node different from the node for this kv // and ensure that this kv has the information within a given time. n.Nodes[1].Gossip.AddInfo( gossip.KeyFirstRangeMetadata, *expectedDesc, time.Hour) maxCycles := 10 n.SimulateNetwork(func(cycle int, network *gossip.SimulationNetwork) bool { desc, err := kv.getFirstRangeDescriptor() if err != nil { if cycle >= maxCycles { t.Errorf("could not get range descriptor after %d cycles", cycle) return false } return true } if !bytes.Equal(desc.StartKey, expectedDesc.StartKey) || !bytes.Equal(desc.EndKey, expectedDesc.EndKey) { t.Errorf("expected first range descriptor %v, instead was %v", expectedDesc, desc) } return false }) n.Stop() }
func main() { // Seed the random number generator for non-determinism across // multiple runs. rand.Seed(time.Now().UTC().UnixNano()) if f := flag.Lookup("alsologtostderr"); f != nil { fmt.Println("Starting simulation. Add -alsologtostderr to see progress.") } flag.Parse() dirName, err := ioutil.TempDir("", "gossip-simulation-") if err != nil { log.Fatalf("could not create temporary directory for gossip simulation output: %s", err) } // Simulation callbacks to run the simulation for cycleCount // cycles. At each cycle % outputEvery, a dot file showing the // state of the network graph is output. nodeCount := 3 gossipInterval := simGossipInterval numCycles := 10 outputEvery := 1 switch *size { case "tiny": // Use default parameters. case "small": nodeCount = 10 case "medium": nodeCount = 25 case "large": nodeCount = 50 gossipInterval = time.Millisecond * 250 case "huge": nodeCount = 100 gossipInterval = time.Second numCycles = 20 outputEvery = 2 case "ginormous": nodeCount = 250 gossipInterval = time.Second * 3 numCycles = 20 outputEvery = 2 default: log.Fatalf("unknown simulation size: %s", *size) } edgeSet := make(map[string]edge) n := gossip.NewSimulationNetwork(nodeCount, *networkType, gossipInterval) n.SimulateNetwork( func(cycle int, network *gossip.SimulationNetwork) bool { if cycle == numCycles { return false } // Update infos. nodes := network.Nodes for i := 0; i < len(nodes); i++ { node := nodes[i].Gossip if err := node.AddInfo(nodes[i].Addr.String(), int64(cycle), time.Hour); err != nil { log.Infof("error updating infos addr: %s cycle: %v: %s", nodes[i].Addr.String(), cycle, err) } } // Output dot graph periodically. if (cycle+1)%outputEvery == 0 { dotFN := fmt.Sprintf("%s/sim-cycle-%d.dot", dirName, cycle) outputDotFile(dotFN, cycle, network, edgeSet) } return true }) n.Stop() // Output instructions for viewing graphs. fmt.Printf("To view simulation graph output run (you must install graphviz):\n\nfor f in %s/*.dot ; do circo $f -Tpng -o $f.png ; echo $f.png ; done\n", dirName) }
func TestVerifyPermissions(t *testing.T) { n := gossip.NewSimulationNetwork(1, "unix", gossip.DefaultTestGossipInterval) kv := NewDistKV(n.Nodes[0].Gossip) config1 := &proto.PermConfig{ Read: []string{"read1", "readAll", "rw", "rwAll"}, Write: []string{"write1", "writeAll", "rw", "rwAll"}} config2 := &proto.PermConfig{ Read: []string{"read2", "readAll", "rw2", "rwAll"}, Write: []string{"write2", "writeAll", "rw2", "rwAll"}} configs := []*storage.PrefixConfig{ {engine.KeyMin, nil, config1}, {engine.Key("a"), nil, config2}, } configMap, err := storage.NewPrefixConfigMap(configs) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } kv.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour) readMethods := storage.ReadMethods writeMethods := storage.WriteMethods readOnlyMethods := make([]string, 0, len(readMethods)) writeOnlyMethods := make([]string, 0, len(writeMethods)) readWriteMethods := make([]string, 0, len(readMethods)+len(writeMethods)) for _, readM := range readMethods { if storage.IsReadOnly(readM) { readOnlyMethods = append(readOnlyMethods, readM) } else { readWriteMethods = append(readWriteMethods, readM) } } for _, writeM := range writeMethods { if !storage.NeedReadPerm(writeM) { writeOnlyMethods = append(writeOnlyMethods, writeM) } } testData := []struct { // Permission-based db methods from the storage package. methods []string user string startKey, endKey engine.Key hasPermission bool }{ // Test permissions within a single range {readOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, true}, {readOnlyMethods, "rw", engine.KeyMin, engine.KeyMin, true}, {readOnlyMethods, "write1", engine.KeyMin, engine.KeyMin, false}, {readOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false}, {readWriteMethods, "rw", engine.KeyMin, engine.KeyMin, true}, {readWriteMethods, "read1", engine.KeyMin, engine.KeyMin, false}, {readWriteMethods, "write1", engine.KeyMin, engine.KeyMin, false}, {writeOnlyMethods, "write1", engine.KeyMin, engine.KeyMin, true}, {writeOnlyMethods, "rw", engine.KeyMin, engine.KeyMin, true}, {writeOnlyMethods, "read1", engine.KeyMin, engine.KeyMin, false}, {writeOnlyMethods, "random", engine.KeyMin, engine.KeyMin, false}, // Test permissions across both ranges {readOnlyMethods, "readAll", engine.KeyMin, engine.Key("b"), true}, {readOnlyMethods, "read1", engine.KeyMin, engine.Key("b"), false}, {readOnlyMethods, "read2", engine.KeyMin, engine.Key("b"), false}, {readOnlyMethods, "random", engine.KeyMin, engine.Key("b"), false}, {readWriteMethods, "rwAll", engine.KeyMin, engine.Key("b"), true}, {readWriteMethods, "rw", engine.KeyMin, engine.Key("b"), false}, {readWriteMethods, "random", engine.KeyMin, engine.Key("b"), false}, {writeOnlyMethods, "writeAll", engine.KeyMin, engine.Key("b"), true}, {writeOnlyMethods, "write1", engine.KeyMin, engine.Key("b"), false}, {writeOnlyMethods, "write2", engine.KeyMin, engine.Key("b"), false}, {writeOnlyMethods, "random", engine.KeyMin, engine.Key("b"), false}, // Test permissions within and around the boundaries of a range, // representatively using rw methods. {readWriteMethods, "rw2", engine.Key("a"), engine.Key("b"), true}, {readWriteMethods, "rwAll", engine.Key("a"), engine.Key("b"), true}, {readWriteMethods, "rw2", engine.Key("a"), engine.Key("a"), true}, {readWriteMethods, "rw2", engine.Key("a"), engine.Key("a1"), true}, {readWriteMethods, "rw2", engine.Key("a"), engine.Key("b1"), false}, {readWriteMethods, "rw2", engine.Key("a3"), engine.Key("a4"), true}, {readWriteMethods, "rw2", engine.Key("a3"), engine.Key("b1"), false}, } for _, test := range testData { for _, method := range test.methods { err := kv.verifyPermissions( method, &proto.RequestHeader{ User: test.user, Key: test.startKey, EndKey: test.endKey}) if err != nil && test.hasPermission { t.Errorf("user: %s should have had permission to %s, err: %s", test.user, method, err.Error()) } else if err == nil && !test.hasPermission { t.Errorf("user: %s should not have had permission to %s", test.user, method) } } } n.Stop() }