func makeTestGossip(t *testing.T) (*gossip.Gossip, func()) { n := simulation.NewNetwork(1, "tcp", gossip.TestInterval) g := n.Nodes[0].Gossip permConfig := &config.PermConfig{ Read: []string{""}, Write: []string{""}, } configMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{ {proto.KeyMin, nil, permConfig}, }) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } if err := g.AddInfo(gossip.KeySentinel, "cluster1", time.Hour); err != nil { t.Fatal(err) } if err := g.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil { t.Fatal(err) } if err := g.AddInfo(gossip.KeyFirstRangeDescriptor, testRangeDescriptor, time.Hour); err != nil { t.Fatal(err) } nodeIDKey := gossip.MakeNodeIDKey(1) if err := g.AddInfo(nodeIDKey, &proto.NodeDescriptor{ NodeID: 1, Address: util.MakeUnresolvedAddr(testAddress.Network(), testAddress.String()), Attrs: proto.Attributes{Attrs: []string{"attr1", "attr2"}}, }, time.Hour); err != nil { t.Fatal(err) } return g, n.Stop }
// TestGCQueueLookupGCPolicy verifies the hierarchical lookup of GC // policy in the event that the longest matching key prefix does not // have a zone configured. func TestGCQueueLookupGCPolicy(t *testing.T) { defer leaktest.AfterTest(t) zoneConfig1 := config.ZoneConfig{ ReplicaAttrs: []proto.Attributes{}, RangeMinBytes: 1 << 10, RangeMaxBytes: 1 << 18, GC: &config.GCPolicy{ TTLSeconds: 60 * 60, // 1 hour only }, } zoneConfig2 := config.ZoneConfig{ ReplicaAttrs: []proto.Attributes{}, RangeMinBytes: 1 << 10, RangeMaxBytes: 1 << 18, // Note that there is no GC set here, so we should select the // hierarchical parent's GC policy; in this case, zoneConfig1. } configs := []*config.PrefixConfig{ {proto.KeyMin, nil, &zoneConfig1}, {proto.Key("/db1"), nil, &zoneConfig2}, } pcc, err := config.NewPrefixConfigMap(configs) if err != nil { t.Fatal(err) } // Setup test context and add new zone config map. This would normally // start a split, but splits are disabled in this testing configuration // because the mock DB does not support splits. tc := testContext{} tc.Start(t) defer tc.Stop() if err := tc.rng.rm.Gossip().AddInfo(gossip.KeyConfigZone, pcc, 0); err != nil { t.Fatal(err) } // Create a new range within "/db1" and verify that lookup of // zone config results in the rng2 := createRange(tc.store, 2, proto.Key("/db1/a"), proto.Key("/db1/b")) if err := tc.store.AddReplicaTest(rng2); err != nil { t.Fatal(err) } gcQ := newGCQueue() gcPolicy, err := gcQ.lookupGCPolicy(rng2) if err != nil { t.Fatal(err) } if ttl := gcPolicy.TTLSeconds; ttl != 60*60 { t.Errorf("expected TTL=%d; got %d", 60*60, ttl) } }
// loadConfigMap scans the config entries under keyPrefix and // instantiates/returns a config map and its sha256 hash. Prefix // configuration maps include accounting, permissions, users, and zones. func loadConfigMap(eng engine.Engine, keyPrefix proto.Key, configI gogoproto.Message) (config.PrefixConfigMap, []byte, error) { // TODO(tschottdorf): Currently this does not handle intents well. kvs, _, err := engine.MVCCScan(eng, keyPrefix, keyPrefix.PrefixEnd(), 0, proto.MaxTimestamp, true /* consistent */, nil) if err != nil { return nil, nil, err } var cfgs []*config.PrefixConfig sha := sha256.New() for _, kv := range kvs { // Instantiate an instance of the config type by unmarshalling // proto encoded config from the Value into a new instance of configI. cfg := reflect.New(reflect.TypeOf(configI).Elem()).Interface().(gogoproto.Message) if err := gogoproto.Unmarshal(kv.Value.Bytes, cfg); err != nil { return nil, nil, util.Errorf("unable to unmarshal config key %s: %s", string(kv.Key), err) } cfgs = append(cfgs, &config.PrefixConfig{Prefix: bytes.TrimPrefix(kv.Key, keyPrefix), Config: cfg}) sha.Write(kv.Value.Bytes) } m, err := config.NewPrefixConfigMap(cfgs) return m, sha.Sum(nil), err }
// TestVerifyPermissions verifies permissions are checked for single // zones and across multiple zones. It also verifies that permissions // are checked hierarchically. func TestVerifyPermissions(t *testing.T) { defer leaktest.AfterTest(t) n := simulation.NewNetwork(1, "tcp", gossip.TestInterval) ds := NewDistSender(nil, n.Nodes[0].Gossip) config1 := &config.PermConfig{ Read: []string{"read1", "readAll", "rw1", "rwAll"}, Write: []string{"write1", "writeAll", "rw1", "rwAll"}} config2 := &config.PermConfig{ Read: []string{"read2", "readAll", "rw2", "rwAll"}, Write: []string{"write2", "writeAll", "rw2", "rwAll"}} configs := []*config.PrefixConfig{ {proto.KeyMin, nil, config1}, {proto.Key("a"), nil, config2}, } configMap, err := config.NewPrefixConfigMap(configs) if err != nil { t.Fatalf("failed to make prefix config map, err: %s", err.Error()) } if err := ds.gossip.AddInfo(gossip.KeyConfigPermission, configMap, time.Hour); err != nil { t.Fatal(err) } allRequestTypes := []proto.Request{ &proto.GetRequest{}, &proto.PutRequest{}, &proto.ConditionalPutRequest{}, &proto.IncrementRequest{}, &proto.DeleteRequest{}, &proto.DeleteRangeRequest{}, &proto.ScanRequest{}, &proto.ReverseScanRequest{}, &proto.EndTransactionRequest{}, &proto.AdminSplitRequest{}, &proto.AdminMergeRequest{}, &proto.HeartbeatTxnRequest{}, &proto.GCRequest{}, &proto.PushTxnRequest{}, &proto.RangeLookupRequest{}, &proto.ResolveIntentRequest{}, &proto.ResolveIntentRangeRequest{}, &proto.MergeRequest{}, &proto.TruncateLogRequest{}, &proto.LeaderLeaseRequest{}, &proto.BatchRequest{}, } var readOnlyRequests []proto.Request var writeOnlyRequests []proto.Request var readWriteRequests []proto.Request for _, r := range allRequestTypes { if proto.IsRead(r) && !proto.IsWrite(r) { readOnlyRequests = append(readOnlyRequests, r) } if proto.IsWrite(r) && !proto.IsRead(r) { writeOnlyRequests = append(writeOnlyRequests, r) } if proto.IsRead(r) && proto.IsWrite(r) { readWriteRequests = append(readWriteRequests, r) } } testData := []struct { // Permission-based db methods from the storage package. requests []proto.Request user string startKey, endKey proto.Key hasPermission bool }{ // Test permissions within a single range {readOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, true}, {readOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {readOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, false}, {readOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false}, {readWriteRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {readWriteRequests, "read1", proto.KeyMin, proto.KeyMin, false}, {readWriteRequests, "write1", proto.KeyMin, proto.KeyMin, false}, {writeOnlyRequests, "write1", proto.KeyMin, proto.KeyMin, true}, {writeOnlyRequests, "rw1", proto.KeyMin, proto.KeyMin, true}, {writeOnlyRequests, "read1", proto.KeyMin, proto.KeyMin, false}, {writeOnlyRequests, "random", proto.KeyMin, proto.KeyMin, false}, // Test permissions hierarchically. {readOnlyRequests, "read1", proto.Key("a"), proto.Key("a1"), true}, {readWriteRequests, "rw1", proto.Key("a"), proto.Key("a1"), true}, {writeOnlyRequests, "write1", proto.Key("a"), proto.Key("a1"), true}, // Test permissions across both ranges. {readOnlyRequests, "readAll", proto.KeyMin, proto.Key("b"), true}, {readOnlyRequests, "read1", proto.KeyMin, proto.Key("b"), true}, {readOnlyRequests, "read2", proto.KeyMin, proto.Key("b"), false}, {readOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false}, {readWriteRequests, "rwAll", proto.KeyMin, proto.Key("b"), true}, {readWriteRequests, "rw1", proto.KeyMin, proto.Key("b"), true}, {readWriteRequests, "random", proto.KeyMin, proto.Key("b"), false}, {writeOnlyRequests, "writeAll", proto.KeyMin, proto.Key("b"), true}, {writeOnlyRequests, "write1", proto.KeyMin, proto.Key("b"), true}, {writeOnlyRequests, "write2", proto.KeyMin, proto.Key("b"), false}, {writeOnlyRequests, "random", proto.KeyMin, proto.Key("b"), false}, // Test permissions within and around the boundaries of a range, // representatively using rw methods. {readWriteRequests, "rw2", proto.Key("a"), proto.Key("b"), true}, {readWriteRequests, "rwAll", proto.Key("a"), proto.Key("b"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("a"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("a1"), true}, {readWriteRequests, "rw2", proto.Key("a"), proto.Key("b1"), false}, {readWriteRequests, "rw2", proto.Key("a3"), proto.Key("a4"), true}, {readWriteRequests, "rw2", proto.Key("a3"), proto.Key("b1"), false}, } for i, test := range testData { for _, r := range test.requests { *r.Header() = proto.RequestHeader{ User: test.user, Key: test.startKey, EndKey: test.endKey, } err := ds.verifyPermissions(r) if err != nil && test.hasPermission { t.Errorf("test %d: user %s should have had permission to %s, err: %s", i, test.user, r.Method(), err.Error()) break } else if err == nil && !test.hasPermission { t.Errorf("test %d: user %s should not have had permission to %s", i, test.user, r.Method()) break } } } n.Stop() }
// TestSplitQueueShouldQueue verifies shouldQueue method correctly // combines splits in accounting and zone configs with the size of // the range. func TestSplitQueueShouldQueue(t *testing.T) { defer leaktest.AfterTest(t) tc := testContext{} tc.Start(t) defer tc.Stop() // Set accounting and zone configs. acctMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{ {proto.KeyMin, nil, config1}, {proto.Key("/dbA"), nil, config2}, }) if err != nil { t.Fatal(err) } if err := tc.gossip.AddInfo(gossip.KeyConfigAccounting, acctMap, 0); err != nil { t.Fatal(err) } zoneMap, err := config.NewPrefixConfigMap([]*config.PrefixConfig{ {proto.KeyMin, nil, &config.ZoneConfig{RangeMaxBytes: 64 << 20}}, {proto.Key("/dbB"), nil, &config.ZoneConfig{RangeMaxBytes: 64 << 20}}, }) if err != nil { t.Fatal(err) } if err := tc.gossip.AddInfo(gossip.KeyConfigZone, zoneMap, 0); err != nil { t.Fatal(err) } testCases := []struct { start, end proto.Key bytes int64 shouldQ bool priority float64 }{ // No intersection, no bytes. {proto.KeyMin, proto.Key("/"), 0, false, 0}, // Intersection in accounting, no bytes. {proto.Key("/"), proto.Key("/dbA1"), 0, true, 1}, // Intersection in zone, no bytes. {proto.Key("/dbA"), proto.Key("/dbC"), 0, true, 1}, // Multiple intersections, no bytes. {proto.KeyMin, proto.KeyMax, 0, true, 1}, // No intersection, max bytes. {proto.KeyMin, proto.Key("/"), 64 << 20, false, 0}, // No intersection, max bytes+1. {proto.KeyMin, proto.Key("/"), 64<<20 + 1, true, 1}, // No intersection, max bytes * 2. {proto.KeyMin, proto.Key("/"), 64 << 21, true, 2}, // Intersection, max bytes +1. {proto.KeyMin, proto.KeyMax, 64<<20 + 1, true, 2}, } splitQ := newSplitQueue(nil, tc.gossip) for i, test := range testCases { if err := tc.rng.stats.SetMVCCStats(tc.rng.rm.Engine(), engine.MVCCStats{KeyBytes: test.bytes}); err != nil { t.Fatal(err) } copy := *tc.rng.Desc() copy.StartKey = test.start copy.EndKey = test.end if err := tc.rng.setDesc(©); err != nil { t.Fatal(err) } shouldQ, priority := splitQ.shouldQueue(proto.ZeroTimestamp, tc.rng) if shouldQ != test.shouldQ { t.Errorf("%d: should queue expected %t; got %t", i, test.shouldQ, shouldQ) } if math.Abs(priority-test.priority) > 0.00001 { t.Errorf("%d: priority expected %f; got %f", i, test.priority, priority) } } }