nkallen (owner)

Revisions

gist: 114639 Download_button fork
public
Description:
Using ScalaCheck to Fuzz a distributed datastore
Public Clone URL: git://gist.github.com/114639.git
Embed All Files: show embed
Ruby #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package com.twitter.service.flock.edges.check
 
import scala.collection.immutable.HashMap
import org.scalacheck._
import net.lag.configgy.{Config, Configgy}
import org.specs.{ScalaCheck, Specification}
 
object EdgesSpec extends Specification with ScalaCheck with Waiter {
  Configgy.configure(System.getProperty("basedir") + "/config/test.conf")
  val username = System.getProperty("db.test.user")
  val password = System.getProperty("db.test.password")
 
  var edges: Edges = null
 
  "Edges" should {
    doBefore {
      val config = Config.fromFile(System.getProperty("basedir") + "/config/" + System.getProperty("stage") + ".conf")
      val username = config("db.username")
      val password = config("db.password")
      val queryEvaluatorFactory = new QueryEvaluatorFactory(username, password)
      val nameServerQueryEvaluator = queryEvaluatorFactory(config("db.name_server_host"), config("db.name_server_database"))
 
      val (e, k) = Edges(config.configMap("edges"), nameServerQueryEvaluator, queryEvaluatorFactory)
      edges = e
    }
 
    doAfter {
      edges.stop_writes()
      val queryEvaluatorFactory = new QueryEvaluatorFactory(username, password)
      val hostConnection = queryEvaluatorFactory("localhost", null)
      hostConnection.execute("DROP DATABASE IF EXISTS flock_shard_005")
    }
 
    "be (eventually) consistent" in {
      new Commands {
        case class State(forward: Map[(Long, Int), Set[Long]], backward: Map[(Long, Int), Set[Long]]) {
          def add (sourceId: Long, listId: Int, destinationId: Long) = {
            val forwardNew = forward.update((sourceId, listId), forward((sourceId, listId)) + destinationId)
            val backwardNew = backward.update((destinationId, listId), backward((destinationId, listId)) + sourceId)
            new State(forwardNew, backwardNew)
          }
          def remove(sourceId: Long, listId: Int, destinationId: Long) = {
            val forwardNew = forward.update((sourceId, listId), forward((sourceId, listId)) - destinationId)
            val backwardNew = backward.update((destinationId, listId), backward((destinationId, listId)) - sourceId)
            new State(forwardNew, backwardNew)
          }
          def count_of_destinations_for(sourceId: Long, listId: Int) = forward(sourceId, listId).size
          def count_of_sources_for(destinationId: Long, listId: Int) = backward(destinationId, listId).size
          def contains(sourceId: Long, listId: Int, destinationId: Long) = forward(sourceId, listId).contains(destinationId)
        }
 
        def initialState = {
          val queryEvaluatorFactory = new QueryEvaluatorFactory(username, password)
          val hostConnection = queryEvaluatorFactory("localhost", null)
          hostConnection.execute("DROP DATABASE IF EXISTS flock_shard_005")
 
          val forwardShard1 = new gen.ShardInfo ("table_005", "flock_shard_005", "localhost", "localhost")
          val backwardShard1 = new gen.ShardInfo("table_006", "flock_shard_005", "localhost", "localhost")
          val forwardShard2 = new gen.ShardInfo ("table_007", "flock_shard_005", "localhost", "localhost")
          val backwardShard2 = new gen.ShardInfo("table_008", "flock_shard_005", "localhost", "localhost")
          val forwardShard3 = new gen.ShardInfo ("table_009", "flock_shard_005", "localhost", "localhost")
          val backwardShard3 = new gen.ShardInfo("table_010", "flock_shard_005", "localhost", "localhost")
          val forwardShard4 = new gen.ShardInfo ("table_011", "flock_shard_005", "localhost", "localhost")
          val backwardShard4 = new gen.ShardInfo("table_012", "flock_shard_005", "localhost", "localhost")
          edges.create_shard(0, gen.List.Follows, forwardShard1, backwardShard1)
          edges.create_shard(0, gen.List.Blocks, forwardShard2, backwardShard2)
          edges.create_shard(0, gen.List.FollowsSms, forwardShard3, backwardShard3)
          edges.create_shard(0, gen.List.RequestsToFollow, forwardShard4, backwardShard4)
 
          val map = new HashMap[(Long, Int), Set[Long]] withDefaultValue Set()
          State(map, map)
        }
 
        case class Add(sourceId: Long, listId: Int, destinationId: Long) extends Command {
          val time = System.currentTimeMillis
 
          def run(s: State) = {
            println("Adding " + (sourceId, listId, destinationId))
            edges.add_at(sourceId, listId, destinationId, time)
          }
 
          def nextState(s: State) = s.add(sourceId, listId, destinationId)
 
          preCondition = s => true
          postCondition = { (s, r) =>
            waitUntil { edges.contains(sourceId, listId, destinationId) }
          }
        }
 
        case class Remove(sourceId: Long, listId: Int, destinationId: Long) extends Command {
          val time = System.currentTimeMillis
 
          def run(s: State) = {
            println("Removing " + (sourceId, listId, destinationId))
            edges.remove_at(sourceId, listId, destinationId, time)
          }
 
          def nextState(s: State) = s.remove(sourceId, listId, destinationId)
 
          preCondition = s => true
          postCondition = { (s, r) =>
            waitUntil { !edges.contains(sourceId, listId, destinationId) }
          }
        }
 
        case class Count(sourceId: Long, listId: Int) extends Command {
          def run(s: State) = {
            println("Count " + (sourceId, listId))
          }
 
          def nextState(s: State) = s
 
          preCondition = s => true
          postCondition = { (s, r) =>
            edges.count_of_destinations_for(sourceId, listId) == s.count_of_destinations_for(sourceId, listId)
            edges.count_of_sources_for(sourceId, listId) == s.count_of_sources_for(sourceId, listId)
          }
        }
 
        case class Contains(sourceId: Long, listId: Int, destinationId: Long) extends Command {
          def run(s: State) = {
            println("Contains " + (sourceId, listId, destinationId))
          }
 
          def nextState(s: State) = s
 
          preCondition = s => true
          postCondition = { (s, r) =>
            edges.contains(sourceId, listId, destinationId) == s.contains(sourceId, listId, destinationId)
          }
        }
 
        case class Get(sourceId: Long, listId: Int, destinationId: Long) extends Command {
          def run(s: State) = {
            println("Get " + (sourceId, listId, destinationId))
          }
 
          def nextState(s: State) = s
 
          preCondition = s => true
          postCondition = { (s, r) =>
            if (s.contains(sourceId, listId, destinationId)) {
              val membership = edges.get(sourceId, listId, destinationId)
              membership.destination_id == destinationId && membership.created_at <= System.currentTimeMillis
            } else {
              try {
                edges.get(sourceId, listId, destinationId)
                false
              } catch {
                case _ => true
              }
            }
          }
        }
 
        val key = for (
          sourceId <- Gen.choose(1L, 10000L);
          destinationId <- Gen.choose(1L, 10000L);
          listId <- Gen.elements(gen.List.Follows, gen.List.Blocks, gen.List.RequestsToFollow, gen.List.FollowsSms)
        ) yield (sourceId, destinationId, listId)
 
        val add = for (
          (sourceId, destinationId, listId) <- key
        ) yield Add(sourceId, listId, destinationId)
 
        val remove = for (
          (sourceId, destinationId, listId) <- key
        ) yield Remove(sourceId, listId, destinationId)
 
        val count = for (
          sourceId <- Gen.choose(1L, 10000L);
          listId <- Gen.elements(gen.List.Follows, gen.List.Blocks, gen.List.RequestsToFollow, gen.List.FollowsSms)
        ) yield Count(sourceId, listId)
 
        val contains = for (
          (sourceId, destinationId, listId) <- key
        ) yield Contains(sourceId, listId, destinationId)
 
        val get = for (
          (sourceId, destinationId, listId) <- key
        ) yield Get(sourceId, listId, destinationId)
 
        def genCommand(s: State): Gen[Command] = for (
          command <- Gen.oneOf(add, remove, count, contains, get)
        ) yield command
 
      }.check
    }
  }
}