github.com/willyham/dosa@v2.3.1-0.20171024181418-1e446d37ee71+incompatible/connectors/random/random.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package random 22 23 import ( 24 "context" 25 26 "math/rand" 27 "time" 28 29 "github.com/satori/go.uuid" 30 "github.com/uber-go/dosa" 31 ) 32 33 const ( 34 maxBlobSize = 32 35 maxStringSize = 64 36 ) 37 38 // Connector is a connector implementation for testing 39 type Connector struct{} 40 41 // CreateIfNotExists always succeeds 42 func (c *Connector) CreateIfNotExists(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error { 43 return nil 44 } 45 46 func randomString(slen int) string { 47 var validRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_-+={[}];:,.<>/?") 48 str := make([]rune, slen) 49 for i := range str { 50 str[i] = validRunes[rand.Intn(len(validRunes))] 51 } 52 return string(str) 53 } 54 55 // Data generates some random data. Because our test is blackbox in a different package, 56 // we have to export this 57 func Data(ei *dosa.EntityInfo, minimumFields []string) map[string]dosa.FieldValue { 58 var result = map[string]dosa.FieldValue{} 59 for _, field := range minimumFields { 60 var v dosa.FieldValue 61 cd := ei.Def.FindColumnDefinition(field) 62 switch cd.Type { 63 case dosa.Int32: 64 v = dosa.FieldValue(rand.Int31()) 65 case dosa.Int64: 66 v = dosa.FieldValue(rand.Int63()) 67 case dosa.Bool: 68 if rand.Intn(2) == 0 { 69 v = dosa.FieldValue(false) 70 } else { 71 v = dosa.FieldValue(true) 72 } 73 case dosa.Blob: 74 // Blobs vary in length from 1 to maxBlobSize bytes 75 blen := rand.Intn(maxBlobSize-1) + 1 76 blob := make([]byte, blen) 77 for i := range blob { 78 blob[i] = byte(rand.Intn(256)) 79 } 80 v = dosa.FieldValue(blob) 81 case dosa.String: 82 slen := rand.Intn(maxStringSize) + 1 83 v = dosa.FieldValue(randomString(slen)) 84 case dosa.Double: 85 v = dosa.FieldValue(rand.Float64()) 86 case dosa.Timestamp: 87 v = dosa.FieldValue(time.Unix(0, rand.Int63()/2)) 88 case dosa.TUUID: 89 v = dosa.FieldValue(uuid.NewV4()) 90 default: 91 panic("invalid type " + cd.Type.String()) 92 93 } 94 result[field] = v 95 } 96 return result 97 } 98 99 // Read always returns random data of the type specified 100 func (c *Connector) Read(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue, minimumFields []string) (map[string]dosa.FieldValue, error) { 101 102 return Data(ei, minimumFields), nil 103 } 104 105 // MultiRead returns a set of random data for each key you specify 106 func (c *Connector) MultiRead(ctx context.Context, ei *dosa.EntityInfo, values []map[string]dosa.FieldValue, minimumFields []string) ([]*dosa.FieldValuesOrError, error) { 107 vals := make([]*dosa.FieldValuesOrError, len(values)) 108 for inx := range values { 109 vals[inx] = &dosa.FieldValuesOrError{ 110 Values: Data(ei, minimumFields), 111 } 112 } 113 return vals, nil 114 } 115 116 // Upsert throws away the data you upsert 117 func (c *Connector) Upsert(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error { 118 return nil 119 } 120 121 // makeErrorSlice is a handy function to make a slice of errors or nil errors 122 func makeErrorSlice(len int, e error) []error { 123 errors := make([]error, len) 124 for inx := 0; inx < len; inx = inx + 1 { 125 errors[inx] = e 126 } 127 return errors 128 } 129 130 // MultiUpsert throws away all the data you upsert, returning a set of no errors 131 func (c *Connector) MultiUpsert(ctx context.Context, ei *dosa.EntityInfo, values []map[string]dosa.FieldValue) ([]error, error) { 132 return makeErrorSlice(len(values), nil), nil 133 } 134 135 // Remove always returns a not found error 136 func (c *Connector) Remove(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error { 137 return nil 138 } 139 140 // RemoveRange removes all entities within the range specified by the columnConditions. 141 func (c *Connector) RemoveRange(ctx context.Context, ei *dosa.EntityInfo, columnConditions map[string][]*dosa.Condition) error { 142 return nil 143 } 144 145 // MultiRemove returns a not found error for each value 146 func (c *Connector) MultiRemove(ctx context.Context, ei *dosa.EntityInfo, multiValues []map[string]dosa.FieldValue) ([]error, error) { 147 return makeErrorSlice(len(multiValues), &dosa.ErrNotFound{}), nil 148 } 149 150 // Range returns a random set of data, and a random continuation token 151 func (c *Connector) Range(ctx context.Context, ei *dosa.EntityInfo, columnConditions map[string][]*dosa.Condition, minimumFields []string, token string, limit int) ([]map[string]dosa.FieldValue, string, error) { 152 vals := make([]map[string]dosa.FieldValue, limit) 153 for inx := range vals { 154 vals[inx] = Data(ei, minimumFields) 155 } 156 return vals, randomString(32), nil 157 } 158 159 // Scan also returns a random set of data, like Range 160 func (c *Connector) Scan(ctx context.Context, ei *dosa.EntityInfo, minimumFields []string, token string, limit int) ([]map[string]dosa.FieldValue, string, error) { 161 return c.Range(ctx, ei, map[string][]*dosa.Condition{}, minimumFields, token, limit) 162 } 163 164 // CheckSchema always returns a slice of int32 values that match its index 165 func (c *Connector) CheckSchema(ctx context.Context, scope, namePrefix string, ed []*dosa.EntityDefinition) (int32, error) { 166 return int32(1), nil 167 } 168 169 // UpsertSchema always returns a slice of int32 values that match its index 170 func (c *Connector) UpsertSchema(ctx context.Context, scope, namePrefix string, ed []*dosa.EntityDefinition) (*dosa.SchemaStatus, error) { 171 return &dosa.SchemaStatus{Version: int32(1), Status: "ACCEPTED"}, nil 172 } 173 174 // CheckSchemaStatus always returns a schema status with version 1 and ACCEPTED 175 func (c *Connector) CheckSchemaStatus(ctx context.Context, scope, namePrefix string, version int32) (*dosa.SchemaStatus, error) { 176 return &dosa.SchemaStatus{ 177 Version: int32(1), 178 Status: "ACCEPTED", 179 }, nil 180 } 181 182 // CreateScope returns success 183 func (c *Connector) CreateScope(ctx context.Context, scope string) error { 184 return nil 185 } 186 187 // TruncateScope returns success 188 func (c *Connector) TruncateScope(ctx context.Context, scope string) error { 189 return nil 190 } 191 192 // DropScope returns success 193 func (c *Connector) DropScope(ctx context.Context, scope string) error { 194 return nil 195 } 196 197 // ScopeExists is not implemented yet 198 func (c *Connector) ScopeExists(ctx context.Context, scope string) (bool, error) { 199 return true, nil 200 } 201 202 // Shutdown always returns nil 203 func (c *Connector) Shutdown() error { 204 return nil 205 } 206 207 // NewConnector creates a new random connector 208 func NewConnector() *Connector { 209 return &Connector{} 210 } 211 212 func init() { 213 dosa.RegisterConnector("random", func(args dosa.CreationArgs) (dosa.Connector, error) { 214 return NewConnector(), nil 215 }) 216 }