summaryrefslogtreecommitdiff
path: root/tests/repair-after-fail-test.py
blob: 0bfb9516fb932c4b53b4159dc1631205be14175a (plain)
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
#!/usr/bin/env python

# Simulate a node saying bye before any of the other nodes have received all
# it's data
#
# - One sender node + a number of observers is created
# - The sender node waits untill all observers joined it's group
# - It then sends out a number of data packets (0,1,2...)
#     Of which the last two data packets are dropped before hitting the mesh
# - The sender node disconnects (sends bye), causing the observers to notice
#    that they didn't receive all previous packets. And send out repair
#    requests for them, which need to be answered by the leaving node.
#
# This can yield false negatives in two cases:
#   * None of the first two bye packets are ever received by any of the other
#     nodes.
#   * While the leaving node did send out (some) repairs, they never reached
#     by any of the other nodes in time.
#
#   Note that  with 4 observers and 30% change of packet drop:
#    - each packet has a 0.8% change of being missed by every observer.
#    - All observers dropping the first two bye packets has a 0.006% chance

from twisted.internet import reactor
from mesh import Mesh, MeshNode, packet_type, BYE, DATA
import sys

NUMOBSERVERS = 4
NUMPACKETS = 10
DELAY = 0.1

nodes = []
# We're optimists
success = True
observers_done = 0

class TestMeshNode(MeshNode):
  nodes = 1
  send_data = True

  def __init__ (self, name, mesh):
    MeshNode.__init__(self, name, mesh)

  def node_connected(self):
    MeshNode.node_connected(self)
    print "Connected"

  def push_packet(self, num):
    self.pushInput (str (num) + "\n")
    if (num >= NUMPACKETS - 3):
      self.send_data = False

    if num == NUMPACKETS -1:
      self.disconnect()

  def sendPacket (self, data):
    if (not self.send_data and packet_type(data) == DATA):
      return
    if packet_type(data) == BYE:
      self.send_data = True
    MeshNode.sendPacket (self, data)


  def newNode (self, data):
    MeshNode.newNode (self, data)
    print "node0 - Added " + data
    self.nodes += 1
    if self.nodes == NUMOBSERVERS + 1:
      print "Everybody who could joined"
      for x in xrange(0, NUMPACKETS):
        reactor.callLater(0.1 * x, (lambda y: self.push_packet(y)), x)

class ObserverMeshNode(MeshNode):
  def __init__ (self, name, mesh):
    MeshNode.__init__(self, name, mesh)

  def leftNode (self, data):
    global observers_done

    MeshNode.leftNode (self, data)
    print data + " left"

    if (data != "node0"):
      print "Wrong node left!"
      success = False
      reactor.stop()
    if (self.mesh.done < observers_done):
      print "Observer done before getting all info"
      success = False
      reactor.stop()

    observers_done += 1

    if (observers_done == NUMOBSERVERS):
      reactor.stop()

class TestMesh(Mesh):
  expected = {}
  done = 0

  def gotOutput(self, node, sender, data):
    global success

    if self.expected.get(node) == None:
      self.expected[node] = 0

    if (self.expected.get(node, int(data)) != int(data)):
      print "Got " + data.rstrip() + " instead of " + \
             str(self.expected[node]) + " from "  + node.name

      success = False
      reactor.crash()

    if not sender in node.peers:
      print "Sender " + sender + " not in node peers"
      success = False
      reactor.crash()

    self.expected[node] = int(data) + 1

    if self.expected[node] == 10:
      self.done += 1

m = TestMesh()

n = TestMeshNode("node0", m)
nodes.append(n)
m.addMeshNode(n)

for x in xrange(0, NUMOBSERVERS):
  n = ObserverMeshNode("observer" + str(x), m)
  nodes.append(n)
  m.addMeshNode(n)

# Connect all nodes to all others. 1024 bytes/s bandwidth, 50ms delay and 0%
# packet loss.. (bandwidth and delay aren't implemented just yet)
m.connect_full(1024, 50, 0.30)

def timeout():
  global success
  print "TIMEOUT!"
  success = False
  reactor.crash()

reactor.callLater(60, timeout)

reactor.run()


if not success:
  print "FAILED"
  sys.exit(-1)

print "SUCCESS"