Exemple #1
0
// Basic test for reed-solomon coding, verifies that standard input
// will produce the correct results.
func TestCoding(t *testing.T) {
	k := 100
	m := common.QuorumSize - k
	bytesPerSegment := 1024

	randomBytes, err := crypto.RandomByteSlice(bytesPerSegment * k)
	if err != nil {
		t.Fatal(err)
	}

	// get hash of original file
	randomBytesHash, err := crypto.CalculateHash(randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// encode original file into a data ring
	ringSegments, err := EncodeRing(k, bytesPerSegment, randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// verify that first k segments are still original data
	originalDataHash, err := crypto.CalculateHash(randomBytes)
	if err != nil {
		t.Fatal(err)
	} else if originalDataHash != randomBytesHash {
		t.Fatal("original data was modified after caling EncodeRing!")
	}

	// reduce file to a set of k segments and print those segments out
	remainingSegments := make([]string, k)
	segmentIndicies := make([]uint8, k)
	for i := m; i < common.QuorumSize; i++ {
		remainingSegments[i-m] = ringSegments[i]
		segmentIndicies[i-m] = uint8(i)
	}

	// recover original data
	recoveredData, err := RebuildSector(k, bytesPerSegment, remainingSegments, segmentIndicies)
	if err != nil {
		t.Fatal(err)
	}

	// compare to hash of data when first generated
	recoveredDataHash, err := crypto.CalculateHash(recoveredData)
	if err != nil {
		t.Fatal(err)
	} else if recoveredDataHash != randomBytesHash {
		t.Fatal("recovered data is different from original data")
	}

	// In every test, we check that the hashes equal
	// every other hash that gets created. This makes
	// me uneasy.
}
Exemple #2
0
// Basic test for reed-solomon coding, verifies that standard input
// will produce the correct results.
func TestCoding(t *testing.T) {
	// set encoding parameters
	k := common.QuorumSize / 2
	m := common.QuorumSize - k
	b := 1024

	// create sector data
	randomBytes, err := crypto.RandomByteSlice(b * k)
	if err != nil {
		t.Fatal(err)
	}

	// create sector
	sec, err := common.NewSector(randomBytes)
	if err != nil {
		t.Fatal(err)
	}

	// calculate encoding parameters
	params := sec.CalculateParams(k)

	// encode data into a Ring
	ring, err := EncodeRing(sec, params)
	if err != nil {
		t.Fatal(err)
	}

	// create Ring from subset of encoded segments
	var newRing []common.Segment
	for i := m; i < common.QuorumSize; i++ {
		newRing = append(newRing, ring[i])
	}

	// recover original data
	newSec, err := RebuildSector(newRing, params)
	if err != nil {
		t.Fatal(err)
	}

	// compare to hash of data when first generated
	recoveredDataHash, err := crypto.CalculateHash(newSec.Data)
	if err != nil {
		t.Fatal(err)
	} else if recoveredDataHash != sec.Hash {
		t.Fatal("recovered data is different from original data")
	}

	// In every test, we check that the hashes equal
	// every other hash that gets created. This makes
	// me uneasy.
}
Exemple #3
0
// Using the current State, newHeartbeat() creates a heartbeat that fulfills all
// of the requirements of the quorum.
func (s *State) newHeartbeat() (hb *heartbeat, err error) {
	hb = new(heartbeat)

	// Generate Entropy
	entropy, err := crypto.RandomByteSlice(common.EntropyVolume)
	if err != nil {
		return
	}
	copy(hb.entropy[:], entropy)

	// more code will be added here

	return
}
Exemple #4
0
// Marshal an Address and see if it unmarshalles to the same value
// Check that bad input is handled correctly
// fuzz over a bunch of random values for Address during long tests
func TestAddressMarshalling(t *testing.T) {
	// marshal, unmarshal, verify at the zero value
	var a Address
	ma := a.Marshal()
	ua, err := UnmarshalAddress(ma)
	if err != nil {
		t.Fatal(err)
	}
	if ua != a {
		t.Fatal("Address not equal after marshalling and unmarshalling!")
	}

	// test that Address marshal handles bad inputs
	var bad []byte
	ua, err = UnmarshalAddress(bad)
	if err == nil {
		t.Error("UnmarshalAddress accepted an unitialized []byte")
	}
	bad = make([]byte, 4)
	ua, err = UnmarshalAddress(bad)
	if err == nil {
		t.Error("UnmarshalAddress accepted a []byte too short to be an address")
	}

	// test marshalling a bunch of random Addresses
	if testing.Short() {
		t.Skip()
	}
	for i := 0; i < 10000; i++ {
		randomBytes, err := crypto.RandomByteSlice(crypto.RandomInt(100) + 1)
		a.Id = Identifier(randomBytes[0]) // random id
		a.Host = string(randomBytes[1:])  // random host
		a.Port = crypto.RandomInt(65536)  // random port

		ma = a.Marshal()
		ua, err = UnmarshalAddress(ma)
		if err != nil {
			t.Error(a.Id, " ", a.Host, " ", a.Port)
			t.Error(err)
		}
		if ua != a {
			t.Error("Fuzzing Test Failed: Marshalled and Unmarshalled address not identical")
			t.Error(a.Id, " ", a.Host, " ", a.Port)
		}
	}
}
Exemple #5
0
func generateSector(q common.Quorum) (s *common.Sector, err error) {
	if q[0].Port == 0 {
		err = fmt.Errorf("you must connect to a quorum first")
		return
	}
	data, err := crypto.RandomByteSlice(70000)
	if err != nil {
		return
	}
	s, err = common.NewSector(data)
	if err != nil {
		return
	}
	SectorDB[s.Hash] = &common.RingHeader{
		Hosts:  q,
		Params: s.CalculateParams(common.QuorumSize / 2),
	}
	return
}
Exemple #6
0
// Using the current State, newHeartbeat() creates a heartbeat that fulfills all
// of the requirements of the quorum.
func (s *State) newHeartbeat() (hb *heartbeat, err error) {
	hb = new(heartbeat)

	// Fetch value used to produce EntropyStage1 in prev. heartbeat
	hb.entropyStage2 = s.storedEntropyStage2

	// Generate EntropyStage2 for next heartbeat
	entropy, err := crypto.RandomByteSlice(common.EntropyVolume)
	if err != nil {
		return
	}
	copy(s.storedEntropyStage2[:], entropy) // convert entropy from slice to byte array

	// Use EntropyStage2 to generate EntropyStage1 for this heartbeat
	hb.entropyStage1, err = crypto.CalculateTruncatedHash(s.storedEntropyStage2[:])
	if err != nil {
		return
	}

	// more code will be added here

	return
}
Exemple #7
0
// TestRPCUploadSector tests the NewRPCServer and uploadFile functions.
// NewRPCServer must properly initialize a RPC server.
// uploadSector must succesfully distribute a Sector among a quorum.
// The uploaded Sector must be successfully reconstructed.
func TestRPCuploadSector(t *testing.T) {
	SectorDB = make(map[crypto.Hash]*common.RingHeader)

	// create RPCServer
	var err error
	router, err = network.NewRPCServer(9985)
	if err != nil {
		t.Fatal("Failed to initialize RPCServer:", err)
	}
	defer router.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	var shs [common.QuorumSize]Server
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qrpc, err := network.NewRPCServer(9000 + i)
		defer qrpc.Close()
		if err != nil {
			t.Fatal("Failed to initialize RPCServer:", err)
		}
		q[i].ID = qrpc.RegisterHandler(&shs[i])
	}

	// create sector
	secData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	sec, err := common.NewSector(secData)
	if err != nil {
		t.Fatal("Failed to create sector:", err)
	}

	// add sector to database
	k := common.QuorumSize / 2
	SectorDB[sec.Hash] = &common.RingHeader{
		Hosts:  q,
		Params: sec.CalculateParams(k),
	}

	// upload sector to quorum
	err = uploadSector(sec)
	if err != nil {
		t.Fatal("Failed to upload file:", err)
	}

	// rebuild file from first k segments
	var newRing []common.Segment
	for i := 0; i < k; i++ {
		newRing = append(newRing, shs[i].seg)
	}

	sec, err = erasure.RebuildSector(newRing, SectorDB[sec.Hash].Params)
	if err != nil {
		t.Fatal("Failed to rebuild file:", err)
	}

	// check hash
	rebuiltHash, err := crypto.CalculateHash(sec.Data)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if sec.Hash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Exemple #8
0
// TestRPCdownloadSector tests the NewRPCServer and downloadSector functions.
// NewRPCServer must properly initialize a RPC server.
// downloadSector must successfully retrieve a Sector from a quorum.
// The downloaded Sector must match the original Sector.
func TestRPCdownloadSector(t *testing.T) {
	SectorDB = make(map[crypto.Hash]*common.RingHeader)

	// create sector
	secData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	sec, err := common.NewSector(secData)
	if err != nil {
		t.Fatal("Failed to create sector:", err)
	}

	k := common.QuorumSize / 2
	params := sec.CalculateParams(k)

	// encode sector
	ring, err := erasure.EncodeRing(sec, params)
	if err != nil {
		t.Fatal("Failed to encode sector data:", err)
	}

	// create RPCServer
	router, err = network.NewRPCServer(9985)
	if err != nil {
		t.Fatal("Failed to initialize RPCServer:", err)
	}
	defer router.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qrpc, err := network.NewRPCServer(9000 + i)
		if err != nil {
			t.Fatal("Failed to initialize RPCServer:", err)
		}
		sh := new(Server)
		sh.seg = ring[i]
		q[i].ID = qrpc.RegisterHandler(sh)
	}

	// add sector to database
	SectorDB[sec.Hash] = &common.RingHeader{
		Hosts:  q,
		Params: params,
	}

	// download file from quorum
	sec, err = downloadSector(sec.Hash)
	if err != nil {
		t.Fatal("Failed to download file:", err)
	}

	// check hash
	rebuiltHash, err := crypto.CalculateHash(sec.Data)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if sec.Hash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Exemple #9
0
// TestTCPUploadFile tests the NewTCPServer and UploadFile functions.
// NewTCPServer must properly initialize a TCP server.
// UploadFile must succesfully distribute a file among a quorum.
// The uploaded file must be successfully reconstructed.
func TestTCPUploadFile(t *testing.T) {
	// create TCPServer
	tcp, err := network.NewTCPServer(9988)
	if err != nil {
		t.Fatal("Failed to initialize TCPServer:", err)
	}
	defer tcp.Close()

	// create quorum
	var q [common.QuorumSize]common.Address
	var uhs [common.QuorumSize]uploadHandler
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qtcp, err := network.NewTCPServer(9000 + i)
		defer qtcp.Close()
		if err != nil {
			t.Fatal("Failed to initialize TCPServer:", err)
		}
		uhs[i].done = make(chan bool, 1)
		q[i].Id = qtcp.AddMessageHandler(&uhs[i]).Id
	}

	// create file
	file, err := os.Create("InputFile")
	if err != nil {
		t.Fatal("Failed to create file \"InputFile\"")
	}
	defer file.Close()
	defer os.Remove("InputFile")

	fileData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	err = ioutil.WriteFile("InputFile", fileData, 0644)
	if err != nil {
		t.Fatal("Failed to write to file InputFile:", err)
	}

	// calculate hash
	origHash, err := crypto.CalculateHash(fileData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	// upload file to quorum
	k := 50
	b, err := UploadFile(tcp, file, k, q)
	if err != nil {
		t.Fatal("Failed to upload file:", err)
	}

	// wait for all participants to complete
	for i := range uhs {
		<-uhs[i].done
	}

	// rebuild file from first k segments
	segments := make([]string, k)
	indices := make([]uint8, k)
	for i := 0; i < k; i++ {
		segments[i] = string(uhs[i].data)
		indices[i] = uint8(uhs[i].index)
	}

	rebuiltData, err := erasure.RebuildSector(k, b, segments, indices)
	if err != nil {
		t.Fatal("Failed to rebuild file:", err)
	}
	// remove padding
	rebuiltData = rebuiltData[:len(fileData)]

	// check hash
	rebuiltHash, err := crypto.CalculateHash(rebuiltData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if origHash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}
Exemple #10
0
// NewTCPServer must properly initialize a TCP server.
// DownloadFile must successfully retrieve a file from a quorum.
// The downloaded file must match the original file.
func TestTCPDownloadFile(t *testing.T) {
	t.Skip()
	// create file
	fileData, err := crypto.RandomByteSlice(70000)
	if err != nil {
		t.Fatal("Could not generate test data:", err)
	}

	// calculate hash
	origHash, err := crypto.CalculateHash(fileData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	// encode file
	k := 50
	bytesPerSegment := len(fileData) / k
	if bytesPerSegment%64 != 0 {
		bytesPerSegment += 64 - (bytesPerSegment % 64)
		padding := k*bytesPerSegment - len(fileData)
		fileData = append(fileData, bytes.Repeat([]byte{0x00}, padding)...)
	}
	segments, err := erasure.EncodeRing(k, bytesPerSegment, fileData)
	if err != nil {
		t.Fatal("Failed to encode file data:", err)
	}

	// create TCPServer
	tcp, err := network.NewTCPServer(9988)
	if err != nil {
		t.Fatal("Failed to initialize TCPServer:", err)
	}
	defer tcp.Close()
	tdh := new(downloadHandler)
	tdh.segments = make([]string, k)
	tdh.indices = make([]uint8, k)
	tdh.k, tdh.b = k, bytesPerSegment
	tcp.AddMessageHandler(tdh)

	// create quorum
	var q [common.QuorumSize]common.Address
	var tfhs [common.QuorumSize]TestFileHandler
	for i := 0; i < common.QuorumSize; i++ {
		q[i] = common.Address{0, "localhost", 9000 + i}
		qtcp, err := network.NewTCPServer(9000 + i)
		if err != nil {
			t.Fatal("Failed to initialize TCPServer:", err)
		}
		tfhs[i].tcpServ = qtcp
		tfhs[i].dest = tcp.Address()
		tfhs[i].data = segments[i]
		tfhs[i].done = make(chan bool, 1)
		q[i].Id = qtcp.AddMessageHandler(&tfhs[i]).Id
	}

	// download file from quorum
	downData, err := DownloadFile(tcp, origHash, len(fileData), k, q)
	if err != nil {
		t.Fatal("Failed to download file:", err)
	}

	// wait for download to complete
	<-tdh.done

	// check hash
	rebuiltHash, err := crypto.CalculateHash(downData)
	if err != nil {
		t.Fatal("Failed to calculate hash:", err)
	}

	if origHash != rebuiltHash {
		t.Fatal("Failed to recover file: hashes do not match")
	}
}