diff --git a/.travis.yml b/.travis.yml index 41e3da95e..3230e843f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,7 @@ matrix: install: - make + +script: + - source setup-env.sh + - python test/test.py diff --git a/lib/python/plasma.py b/lib/python/plasma.py index 4ce8fdb5c..69361d63c 100644 --- a/lib/python/plasma.py +++ b/lib/python/plasma.py @@ -1,3 +1,4 @@ +import os import socket import ctypes @@ -33,13 +34,14 @@ def make_plasma_id(string): class PlasmaClient(object): def __init__(self, socket_name): - self.client = ctypes.cdll.LoadLibrary("../../build/plasma_client.so") + plasma_client_library = os.path.join(os.path.abspath(os.path.dirname(__file__)), "../../build/plasma_client.so") + self.client = ctypes.cdll.LoadLibrary(plasma_client_library) self.client.plasma_store_connect.restype = ctypes.c_int self.client.plasma_create.argtypes = [ctypes.c_int, PlasmaID, ctypes.c_int64] self.client.plasma_create.restype = PlasmaBuffer - + self.client.plasma_get.argtypes = [ctypes.c_int, PlasmaID] self.client.plasma_get.restype = PlasmaBuffer @@ -63,8 +65,6 @@ class PlasmaClient(object): def get(self, object_id): buf = self.client.plasma_get(self.sock, make_plasma_id(object_id)) return self.buffer_from_memory(buf.data, buf.size) - + def seal(self, object_id): self.client.plasma_seal(self.sock, make_plasma_id(object_id)) - - diff --git a/setup-env.sh b/setup-env.sh new file mode 100644 index 000000000..a1b2cb4b1 --- /dev/null +++ b/setup-env.sh @@ -0,0 +1,5 @@ +echo "Adding Plasma to PYTHONPATH" 1>&2 + +ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE:-$0}")"; pwd) + +export PYTHONPATH="$ROOT_DIR/lib/python/:$PYTHONPATH" diff --git a/src/plasma_client.c b/src/plasma_client.c index cd60d659b..5dd36ae7e 100644 --- a/src/plasma_client.c +++ b/src/plasma_client.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "plasma.h" #include "fling.h" @@ -77,7 +77,18 @@ int plasma_store_connect(const char* socket_name) { memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, socket_name, sizeof(addr.sun_path)-1); - if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { + // Try to connect to the Plasma store. If unsuccessful, retry several times. + int connected_successfully = 0; + for (int num_attempts = 0; num_attempts < 50; ++num_attempts) { + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) { + connected_successfully = 1; + break; + } + // Sleep for 100 milliseconds. + usleep(100000); + } + // If we could not connect to the Plasma store, exit. + if (!connected_successfully) { LOG_ERR("could not connect to store %s", socket_name); exit(-1); } diff --git a/test/test.py b/test/test.py new file mode 100644 index 000000000..6d4bee003 --- /dev/null +++ b/test/test.py @@ -0,0 +1,59 @@ +import os +import subprocess +import sys +import unittest + +import plasma + +class TestPlasmaAPI(unittest.TestCase): + + def setUp(self): + # Start Plasma. + plasma_store_executable = os.path.join(os.path.abspath(os.path.dirname(__file__)), "../build/plasma_store") + self.p = subprocess.Popen([plasma_store_executable, "-s", "/tmp/store"]) + # Connect to Plasma. + self.plasma_client = plasma.PlasmaClient("/tmp/store") + + def tearDown(self): + # Kill the plasma stoe process. + self.p.kill() + + def test_create(self): + # Create an object string. + object_id = "id" + 18 * "x" + # Create a new buffer and write to it. + length = 1000 + memory_buffer = self.plasma_client.create(object_id, length) + for i in range(length): + memory_buffer[i] = chr(i % 256) + # Seal the object. + self.plasma_client.seal(object_id) + # Get the object. + memory_buffer = self.plasma_client.get(object_id) + for i in range(length): + self.assertEqual(memory_buffer[i], chr(i % 256)) + + def test_illegal_functionality(self): + # Create an object string. + object_id = "id" + 18 * "x" + # Create a new buffer and write to it. + length = 1000 + memory_buffer = self.plasma_client.create(object_id, length) + # Make sure we cannot access memory out of bounds. + self.assertRaises(Exception, lambda : memory_buffer[length]) + # Seal the object. + self.plasma_client.seal(object_id) + # This test is commented out because it currently fails. + # # Make sure the object is ready only now. + # def illegal_assignment(): + # memory_buffer[0] = chr(0) + # self.assertRaises(Exception, illegal_assignment) + # Get the object. + memory_buffer = self.plasma_client.get(object_id) + # Make sure the object is read only. + def illegal_assignment(): + memory_buffer[0] = chr(0) + self.assertRaises(Exception, illegal_assignment) + +if __name__ == "__main__": + unittest.main(verbosity=2)