示例#1
0
 def __init__(self, *args, **kwargs):
     self.client = RESTOpenTSDBClient("localhost",4242)
     try:
         self.version = int(self.client.get_version()["version"].split('.')[0])
     except:
         self.version = None
     super(TestTreeManipulation, self).__init__(*args, **kwargs)
示例#2
0
    def test_client(self):
        # create
        td = OpenTSDBTreeDefinition("")
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        self.assertRaises(ValueError, td.create, client)
        td = OpenTSDBTreeDefinition(self.getUniqueString(),
                                    self.getUniqueString(),
                                    self.getUniqueString())
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        tdmap_before = td.getMap()
        response = td.getMap()
        response["created"] = int(time.time())
        response["treeId"] = self.getUniqueInteger()

        def my_post(url, data):
            return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'post', my_post)
        td.create(
            client
        )  # after this, the object must have a created value and a treeId.
        tdmap_after = td.getMap()
        for k in tdmap_before:
            self.assertEqual(tdmap_before[k], tdmap_after[k])
        self.assertIsNot(tdmap_after["created"], None)
        self.assertEqual(tdmap_after["created"], response["created"])
        self.assertEqual(tdmap_after["treeId"], response["treeId"])
        self.assertRaises(ValueError, td.create,
                          client)  # a second call to creates should fail
        # saveTo
        td.description = self.getUniqueString()  # change the description
        response = td.getMap()

        def my_post(url, data):
            return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'post', my_post)
        td.saveTo(client)

        # delete
        def my_delete(url, data):
            return FakeResponse(204, "")

        self.patch(requests, 'delete', my_delete)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        td.delete(client)
        self.assertEqual(None, td.treeId)
        self.assertEqual(None, td.created)
        self.assertEqual({}, td.rules)
示例#3
0
    def test_client(self):
        """test the interaction with the client with request emulation"""

        # load
        a = OpenTSDBAnnotation(1369141261, 1369141262, "000001000001000001",
                               "Network Outage",
                               "Switch #5 died and was replaced", {
                                   "owner": "jdoe",
                                   "dept": "ops"
                               })
        b = OpenTSDBAnnotation(1369141261, 1369141262, "000001000001000001")

        def my_get(url, data):
            return FakeResponse(200, json.dumps(a.getMap()))

        self.patch(requests, 'get', my_get)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        b.loadFrom(client)
        self.assertEqual(a.getMap(), b.getMap())

        # save
        a = OpenTSDBAnnotation(1369141261, 1369141262, "000001000001000001",
                               "Network Outage",
                               "Switch #5 died and was replaced", {
                                   "owner": "jdoe",
                                   "dept": "ops"
                               })

        def my_post(url, data):
            return FakeResponse(200, data)

        self.patch(requests, 'post', my_post)
        a.saveTo(client)

        # delete
        def my_delete(url, data):
            return FakeResponse(200, data)

        self.patch(requests, 'delete', my_delete)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        a = OpenTSDBAnnotation(1369141261, 1369141262, "000001000001000001",
                               "Network Outage",
                               "Switch #5 died and was replaced", {
                                   "owner": "jdoe",
                                   "dept": "ops"
                               })
        a.delete(client)
示例#4
0
    def test_client(self):
        m = OpenTSDBMeasurement(
            OpenTSDBTimeSeries("sys.cpu.nice", {
                "host": "web01",
                "dc": "lga"
            }, '0000150000070010D0'), int(time.time()),
            self.getUniqueInteger())

        def my_post(url, data):
            return FakeResponse(204, "")

        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        m.saveTo(client)
示例#5
0
    def test_client(self):
        # use the client... this should just work.
        r = OpenTSDBRule(abs(self.getUniqueInteger()),
                         level=1,
                         order=0,
                         type="METRIC",
                         description="Split the metric on periods",
                         separator="\\.")

        # saveTo
        def my_post(url, data):
            return FakeResponse(200, json.dumps(r.getMap()))

        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        r.saveTo(client)

        # delete
        def my_delete(url, data):
            return FakeResponse(204, "")

        self.patch(requests, 'delete', my_delete)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        r.delete(client)
示例#6
0
class TestTreeManipulation(TestCase):
    """Tests implying a running test server on localhost
       tree manipulation
       separate class with preparation code to fill fake data and termination code to cleanup"""

    def __init__(self, *args, **kwargs):
        self.client = RESTOpenTSDBClient("localhost",4242)
        try:
            self.version = int(self.client.get_version()["version"].split('.')[0])
        except:
            self.version = None
        super(TestTreeManipulation, self).__init__(*args, **kwargs)


    def test_tree(self):
        if self.version != 2: self.skipTest("No server running")
示例#7
0
    def test_checkArguments(self):
        """Test the top-level method to validate arguments of the client methods."""
        
        #the function uses the frame to get the context. It cannot be validated standalone.
        #we therefore use the client.delete_annotation method, disabling the requests.delete method.
        #for the method to work, it is enough for the delete replacement to return data as the FakeResponse content.

        def my_delete(url,data): return FakeResponse(200,data)
        self.patch(requests, 'delete', my_delete)
        client = RESTOpenTSDBClient("localhost",4242,"2.2.0")

        # this should pass
        client.delete_annotation(abs(self.getUniqueInteger()),abs(self.getUniqueInteger()),"000001000001000001")
        client.delete_annotation(abs(self.getUniqueInteger()),abs(self.getUniqueInteger()))

        # this should fail. We check the error template.
        e = self.assertRaises(ValueError,client.delete_annotation,-1)
        self.assertEqual("delete_annotation::startTime: got -1",e.message)
        e = self.assertRaises(ValueError,client.delete_annotation,"2016-01-01")
        self.assertEqual("delete_annotation::startTime: got 2016-01-01",e.message)
        e = self.assertRaises(TypeError,client.delete_annotation,3.4)
        self.assertEqual("delete_annotation::startTime: Type mismatch", e.message)
示例#8
0
    def test_client(self):
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01", "dc": "lga"})
        response = {
            "metric": {
                "sys.cpu.nice": "000042"
            },
            "tagv": {
                "web01": "00001A",
                "lga": "00001B"
            },
            "tagk": {
                "host": "000012",
                "dc": "000013"
            }
        }

        def my_post(url, data):
            return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.assign_uid(client)
        self.assertEqual("000042", ts.metric_meta.uid)
        self.assertEqual("00001A", ts.tagv_meta["web01"].uid)
        self.assertEqual("00001B", ts.tagv_meta["lga"].uid)
        self.assertEqual("000012", ts.tagk_meta["host"].uid)
        self.assertEqual("000013", ts.tagk_meta["dc"].uid)

        # we now test what happens if some uids are already assigned. Here the metric.
        response = {
            "metric": {},
            "metric_errors": {
                "sys.cpu.nice": "Name already exists with UID: 000042"
            },
            "tagv": {
                "web01": "00001A",
                "lga": "00001B"
            },
            "tagk": {
                "host": "000012",
                "dc": "000013"
            }
        }

        def my_post(url, data):
            return FakeResponse(400, json.dumps(response))

        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.assign_uid(client)
        self.assertEqual("000042", ts.metric_meta.uid)
        self.assertEqual("00001A", ts.tagv_meta["web01"].uid)
        self.assertEqual("00001B", ts.tagv_meta["lga"].uid)
        self.assertEqual("000012", ts.tagk_meta["host"].uid)
        self.assertEqual("000013", ts.tagk_meta["dc"].uid)

        # we now test what happens if some uids are already assigned. Here one tag.
        response = {
            "metric": {
                "sys.cpu.nice": "000042"
            },
            "tagv": {
                "web01": "00001A"
            },
            "tagv_errors": {
                "lga": "00001B"
            },
            "tagk": {
                "dc": "000013"
            },
            "tagk_errors": {
                "host": "Name already exists with UID: 0007E5"
            }
        }

        def my_post(url, data):
            return FakeResponse(400, json.dumps(response))

        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.assign_uid(client)
        self.assertEqual("000042", ts.metric_meta.uid)
        self.assertEqual("00001A", ts.tagv_meta["web01"].uid)
        self.assertEqual("00001B", ts.tagv_meta["lga"].uid)
        self.assertEqual("0007E5", ts.tagk_meta["host"].uid)
        self.assertEqual("000013", ts.tagk_meta["dc"].uid)

        # test the loadFrom functionality
        # case 1: tsuid set
        ts = OpenTSDBTimeSeries(tsuid='000005000001000002000002000006')
        #    1a get_tsmeta works -> returns meta
        response = {
            "tsuid":
            "000005000001000002000002000006",
            "metric": {
                "uid": "00002A",
                "type": "METRIC",
                "name": "sys.cpu.nice",
                "description": "System Nice CPU Time",
                "notes": "",
                "created": 1350425579,
                "custom": None,
                "displayName": ""
            },
            "tags": [{
                "uid": "000001",
                "type": "TAGK",
                "name": "host",
                "description": "Server Hostname",
                "notes": "",
                "created": 1350425579,
                "custom": None,
                "displayName": "host"
            }, {
                "uid": "000001",
                "type": "TAGV",
                "name": "web01",
                "description": "Website hosting server",
                "notes": "",
                "created": 1350425579,
                "custom": None,
                "displayName": "Web Server 01"
            }],
            "description":
            "Measures CPU activity",
            "notes":
            "",
            "created":
            1350425579,
            "units":
            "",
            "retention":
            0,
            "max":
            "NaN",
            "min":
            "NaN",
            "custom": {
                "owner": "Jane Doe",
                "department": "Operations",
                "assetTag": "12345"
            },
            "displayName":
            "",
            "dataType":
            "absolute",
            "lastReceived":
            1350425590,
            "totalDatapoints":
            12532
        }
        reference = {
            'metadata': {
                'created': 1350425579,
                'custom': {
                    'assetTag': '12345',
                    'department': 'Operations',
                    'owner': 'Jane Doe'
                },
                'dataType': 'absolute',
                'description': 'Measures CPU activity',
                'displayName': '',
                'lastReceived': 1350425590,
                'max': 'NaN',
                'min': 'NaN',
                'notes': '',
                'retention': 0,
                'totalDatapoints': 12532,
                'tsuid': '000005000001000002000002000006',
                'units': ''
            },
            'metric': 'sys.cpu.nice',
            'metric_meta': {
                'created': 1350425579,
                'custom': {},
                'description': 'System Nice CPU Time',
                'displayName': '',
                'name': 'sys.cpu.nice',
                'notes': '',
                'type': 'METRIC',
                'uid': '00002A'
            },
            'tagk_meta': {
                'host': {
                    'created': 1350425579,
                    'custom': {},
                    'description': 'Server Hostname',
                    'displayName': 'host',
                    'name': 'host',
                    'notes': '',
                    'type': 'TAGK',
                    'uid': '000001'
                }
            },
            'tags': {
                'host': 'web01'
            },
            'tagv_meta': {
                'web01': {
                    'created': 1350425579,
                    'custom': {},
                    'description': 'Website hosting server',
                    'displayName': 'Web Server 01',
                    'name': 'web01',
                    'notes': '',
                    'type': 'TAGV',
                    'uid': '000001'
                }
            }
        }
        search_response = {
            'totalResults':
            1,
            'metric':
            '*',
            'results': [{
                'tsuid': '000005000001000002000002000006',
                'metric': 'sys.cpu.nice',
                'tags': {
                    'host': 'web01'
                }
            }],
            'startIndex':
            0,
            'limit':
            25,
            'time':
            25491.0,
            'query':
            '',
            'type':
            'LOOKUP'
        }

        def my_get(url, params):
            if "use_meta" in params:
                return FakeResponse(200, json.dumps(search_response))
            else:
                return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'get', my_get)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.loadFrom(client)
        self.assertEqual(ts.metadata.created, 1350425579)
        self.assertEqual(reference, ts.getMap(full=True))

        #    1b get_tsmeta fails -> exception -> set_tsmeta returns meta
        def my_get(url, params):
            return FakeResponse(404, "")

        def my_post(url, data, params):
            return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'get', my_get)
        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01"},
                                '0000150000070010D0')
        ts.loadFrom(client)
        self.assertEqual(reference, ts.getMap(full=True))
        # case 2: metric and tags set
        #    2a get_ts_meta returns one entry -> meta
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01"})
        response = [response]

        def my_get(url, params):
            return FakeResponse(200, json.dumps(response))

        self.patch(requests, 'get', my_get)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.loadFrom(client)
        self.assertEqual(ts.metadata.created, 1350425579)
        self.assertEqual(reference, ts.getMap(full=True))
        #    2b get_ts_meta returns no entry -> set_tsmeta with query string -> meta
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01"})
        get_response = []
        post_response = response[0]

        def my_get(url, params):
            return FakeResponse(200, json.dumps(get_response))

        def my_post(url, data, params):
            return FakeResponse(200, json.dumps(post_response))

        self.patch(requests, 'get', my_get)
        self.patch(requests, 'post', my_post)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.loadFrom(client)
        self.assertEqual(ts.metadata.created, 1350425579)
        self.assertEqual(reference, ts.getMap(full=True))
        #    2c get_ts_meta returns two entries -> exception
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01"})
        get_response = [post_response, post_response]

        def my_get(url, params):
            return FakeResponse(200, json.dumps(get_response))

        self.patch(requests, 'get', my_get)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        self.assertRaises(ValueError, ts.loadFrom, client)
        # saveTo - just check that it runs.
        ts = OpenTSDBTimeSeries("sys.cpu.nice", {"host": "web01"},
                                '000005000001000002000002000006')
        ts.metric_meta.uid = "00002A"
        ts.metric_meta.type = "metric"
        ts.tagk_meta["host"].uid = "000001"
        ts.tagk_meta["host"].type = "tagk"
        ts.tagv_meta["web01"].uid = "000001"
        ts.tagv_meta["web01"].type = "tagv"

        def my_post(url, data, params=None):
            return FakeResponse(
                200,
                json.dumps({
                    "tsuid": '000005000001000002000002000006',
                    "uid": "00002A",
                    "type": "METRIC"
                }))

        self.patch(requests, 'post',
                   my_post)  # just enough to make it run, but meaningless
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.saveTo(client)

        # deleteMeta - just check that it runs.
        def my_delete(url, data):
            return FakeResponse(204, "")

        self.patch(requests, 'delete', my_delete)
        client = RESTOpenTSDBClient("localhost", 4242, "2.2.0")
        ts.deleteMeta(client, True)
示例#9
0
class TestClientServer(TestCase):
    """Tests implying a running test server on localhost"""

    def __init__(self, *args, **kwargs):
        self.client = RESTOpenTSDBClient("localhost",4242)
        try:
            self.version = int(self.client.get_version()["version"].split('.')[0])
        except:
            self.version = None
        super(TestClientServer, self).__init__(*args, **kwargs)

    # simple info methods

    def test_get_statistics(self):
        if self.version != 2: self.skipTest("No server running")
        stats= self.client.get_statistics()
        # should return a list of measurements.
        for s in stats:
            self.assertIsInstance(s,OpenTSDBMeasurement)

    def test_get_filters(self):
        if self.version != 2: self.skipTest("No server running")
        filters = self.client.get_filters()
        # default filters should be there
        for std in ["not_iliteral_or","literal_or","wildcard","iliteral_or","regexp","iwildcard","not_literal_or"]:
            self.assertIn(std,filters)

    def test_get_configuration(self):
        if self.version != 2: self.skipTest("No server running")
        conf = self.client.get_configuration()
        # all configuration items start with "tsd."
        for c in conf:
            self.assertEqual("tsd.",c[:4])

    def test_drop_caches(self):
        if self.version != 2: self.skipTest("No server running")
        result = self.client.drop_caches()
        # this should always return this
        expected = {'status': '200', 'message': 'Caches dropped'}
        self.assertEqual(expected,result)

    def test_get_serializers(self):
        if self.version != 2: self.skipTest("No server running")
        serializers = self.client.get_serializers()
        # This endpoint should always return data with the JSON serializer as the default.
        self.assertEqual(any(s["serializer"]=="json" for s in serializers),True)

    def test_get_version(self):
        if self.version != 2: self.skipTest("No server running")
        v = self.client.get_version()
        self.assertEqual(2,int(v["version"].split('.')[0]))
        self.assertEqual(['full_revision', 'repo_status', 'timestamp', 'short_revision', 'repo', 'host', 'version', 'user'],list(v.keys()))

    def test_get_aggregators(self):
        if self.version != 2: self.skipTest("No server running")
        a = self.client.get_aggregators()
        for std in ['sum', 'min', 'avg', 'dev', 'max', 'count']:
            self.assertIn(std,a)

    def test_assign_uid(self):
        if self.version != 2: self.skipTest("No server running")
        # nb: this will assign a uid to a random tagk at least.
        # the first time, it may also create other uids
        # the next times, there should be existing uids.
        uid = str(uuid.uuid4())
        response = self.client.assign_uid(["sys.cpu.0","sys.cpu.1","illegal!character"],["host"],["web01","web02","web03",uid])
        self.assertIn('illegal!character', response["metric_errors"])
        self.assertIn(uid,response["tagv"])

    def test_put_measurements(self):
        if self.version != 2: self.skipTest("No server running")
        # basic functional tests
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": "web01","dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        meas = OpenTSDBMeasurement(ts,int(time.time()),18)
        response = self.client.put_measurements([meas], details=True) # this should work
        self.assertEqual(response["success"],1)
        wrong_meas = OpenTSDBMeasurement(OpenTSDBTimeSeries(str(uuid.uuid4()),{"host": "web01","dc": "lga"}),int(time.time()),18)
        response = self.client.put_measurements([wrong_meas], details=True) # this should fail with 'Unknown metric' error
        self.assertEqual('Unknown metric',response["errors"][0]["error"])
        # check options: summary, details, sync, compress
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": "web01","dc": "lga"})
        meas = OpenTSDBMeasurement(ts,int(time.time()),15)
        response = self.client.put_measurements([meas])
        self.assertEqual(None,response)
        response = self.client.put_measurements([meas], summary=True)
        self.assertEqual(response["success"],1)
        for i in ["failed", "success"]:
                self.assertIn(i,response)
        response = self.client.put_measurements([meas], sync=True, sync_timeout=10000)
        meas = OpenTSDBMeasurement(ts,int(time.time()),10)
        response = self.client.put_measurements([meas], compress=True)

    def test_annotation(self):
        if self.version != 2: self.skipTest("No server running")
        now = int(time.time())
        myAnnotation = self.client.set_annotation(now,
                                                  description="Testing Annotations", 
                                                  notes="These would be details about the event, the description is just a summary", 
                                                  custom={"owner": "jdoe","dept": "ops"})
        expected = {'custom':{"owner": "jdoe","dept": "ops"},'description': 'Testing Annotations',
                    'notes': 'These would be details about the event, the description is just a summary',
                    'startTime': now}

        self.assertEqual(expected,myAnnotation.getMap())

        myAnnotation_readback = self.client.get_annotation(now)
        self.assertEqual(expected,myAnnotation_readback.getMap())

        myAnnotation_modified = self.client.set_annotation(now,description="Testing Annotations - modified")
        expected["description"]="Testing Annotations - modified"
        self.assertEqual(expected,myAnnotation_modified.getMap())

        myAnnotation_readback = self.client.get_annotation(now)
        self.assertEqual(expected,myAnnotation_readback.getMap())
        
        response = self.client.delete_annotation(now)
        self.assertEqual(None,response)

        error = self.assertRaises(OpenTSDBError,self.client.get_annotation,now)
        self.assertEqual(error.code,404)
        self.assertEqual(error.message,"Unable to locate annotation in storage")

        # do the same using the annotation object

        now = int(time.time())
        myAnnotation = OpenTSDBAnnotation(now,
                                          description="Testing Annotations", 
                                          notes="These would be details about the event, the description is just a summary", 
                                          custom={"owner": "jdoe","dept": "ops"})
        myAnnotation.saveTo(self.client)
        expected = {'custom':{"owner": "jdoe","dept": "ops"},'description': 'Testing Annotations',
                    'notes': 'These would be details about the event, the description is just a summary',
                    'startTime': now}
        self.assertEqual(expected,myAnnotation.getMap())
        
        myAnnotation_readback = OpenTSDBAnnotation(now).loadFrom(self.client)
        self.assertEqual(expected,myAnnotation_readback.getMap())

        myAnnotation.description = "Testing Annotations - modified"
        expected["description"]="Testing Annotations - modified"
        myAnnotation.saveTo(self.client)
        self.assertEqual(expected,myAnnotation.getMap())

        myAnnotation.delete(self.client)
        time.sleep(5)
        error = self.assertRaises(OpenTSDBError,myAnnotation.loadFrom,self.client)
        self.assertEqual(error.code,404)
        self.assertEqual(error.message,"Unable to locate annotation in storage")

    # ts meta (R/W) _ includes define_retention

    def test_tsmeta(self):
        if self.version != 2: self.skipTest("No server running")

        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        try:
            tsuid = self.client.set_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)["tsuid"] #get the tsuid - could be done via the OpenTSDBTimeSeries class
        except OpenTSDBError: # this may happen if the TS meta already exists from a previous aborted test.
            tsuid = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["tsuid"]

        # set, get, check, delete, check
        description = self.getUniqueString()
        displayName = self.getUniqueString()
        notes = self.getUniqueString()
        custom = { "from":self.getUniqueString(), "to":self.getUniqueString() }
        units = self.getUniqueString()
        dataType = self.getUniqueString()
        retention = self.getUniqueInteger()
        minimum = float(self.getUniqueInteger())
        maximum = float(self.getUniqueInteger())
        r = self.client.set_tsmeta(tsuid,description=description, displayName=displayName, notes=notes, custom=custom, units=units, dataType=dataType, retention=retention, minimum=minimum, maximum=maximum)
        self.assertEqual(description, r["description"])
        r2 = self.client.get_tsmeta(tsuid)
        self.assertEqual(r,r2)
        self.client.define_retention(tsuid,14)
        self.assertEqual(None,self.client.delete_tsmeta(tsuid))
        time.sleep(5)
        e = self.assertRaises(OpenTSDBError,self.client.get_tsmeta,tsuid)
        self.assertEqual(e.code,404)
        self.assertEqual(e.message,"Could not find Timeseries meta data")

    # uid meta (R/W)

    def test_uidmeta(self):
        if self.version != 2: self.skipTest("No server running")

        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        try:
            tsuid = self.client.set_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)["tsuid"] #get the tsuid - could be done via the OpenTSDBTimeSeries class
        except OpenTSDBError: # this may happen if the TS meta already exists from a previous aborted test.
            tsuid = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["tsuid"]

        # get one uid and its meta from the timeseries
        uidmeta = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["metric"]
        uid = uidmeta["uid"]

        # set, get, check, delete, check
        description = self.getUniqueString()
        displayName = self.getUniqueString()
        notes = self.getUniqueString()
        custom = { "from":self.getUniqueString(), "to":self.getUniqueString() }
        r = self.client.set_uidmeta(uid, "metric", description=description, displayName=displayName, notes=notes, custom=custom)
        self.assertEqual(r["description"],description)
        self.assertEqual(r["displayName"],displayName)
        self.assertEqual(r["notes"],notes)
        self.assertEqual(r["custom"],custom)
        r2 = self.client.get_uidmeta(uid, "metric")
        self.assertEqual(r2,r)
        self.client.delete_uidmeta(uid, "metric")
        time.sleep(5)
        r3 = self.client.get_uidmeta(uid, "metric")
        default={"uid":uid,"type":"METRIC","name":"sys.cpu.nice","description":"","notes":"","created":0,"custom":None,"displayName":""}
        self.assertEqual(default,r3)

    # same using the objects...

    def test_OpenTSDBTimeSeries_meta(self):
        # this combines functionalities from both tsmeta and uidmeta
        if self.version != 2: self.skipTest("No server running")
        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        try:
            tsuid = self.client.set_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)["tsuid"] #get the tsuid - could be done via the OpenTSDBTimeSeries class
        except OpenTSDBError: # this may happen if the TS meta already exists from a previous aborted test.
            tsuid = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["tsuid"]

        # load full metadata, including tsuid
        ts.loadFrom(self.client)
        self.assertEqual(tsuid,ts.metadata.tsuid)

        # set, get, check, delete, check
        description = self.getUniqueString()
        displayName = self.getUniqueString()
        notes = self.getUniqueString()
        custom = { "from":self.getUniqueString(), "to":self.getUniqueString() }
        units = self.getUniqueString()
        dataType = self.getUniqueString()
        retention = self.getUniqueInteger()
        minimum = float(self.getUniqueInteger())
        maximum = float(self.getUniqueInteger())
        ts.metadata.set(description=description, displayName=displayName, notes=notes, custom=custom, units=units, dataType=dataType, retention=retention, minimum=minimum, maximum=maximum)
        ts.tagk_meta["host"].description="The host name"
        ts.tagk_meta["host"].displayName="hostname"
        ts.tagv_meta[host].description="A randomly generated hostname"
        ts.tagv_meta[host].notes="Just for the sake of testing"
        ts.saveTo(self.client)
        self.assertEqual(description,ts.metadata.description)
        ts.loadFrom(self.client)
        self.assertEqual(description,ts.metadata.description)
        ts.deleteMeta(self.client)
        time.sleep(5)
        e = self.assertRaises(OpenTSDBError,self.client.get_tsmeta,tsuid)
        self.assertEqual(e.code,404)
        self.assertEqual(e.message,"Could not find Timeseries meta data")

    # queries

    def test_suggest(self):
        if self.version != 2: self.skipTest("No server running")
        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known

        allhosts = self.client.suggest("tagv",host[0])
        thishost= self.client.suggest("tagv",host)
        somehosts = self.client.suggest("tagv",host[:len(host)/2])

        self.assertIn(host,allhosts)
        self.assertIn(host,thishost)
        self.assertIn(host,somehosts)
        
        self.assertIn("host",self.client.suggest("tagk","h"))

        self.assertIn("sys.cpu.nice",self.client.suggest("metrics","sys"))

    def test_search(self):
        if self.version != 2: self.skipTest("No server running")
        #limited to /api/search/lookup since others rely on plugins...
        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        try:
            tsuid = self.client.set_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)["tsuid"] #get the tsuid - could be done via the OpenTSDBTimeSeries class
        except OpenTSDBError: # this may happen if the TS meta already exists from a previous aborted test.
            tsuid = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["tsuid"]

        r = self.client.search("LOOKUP",metric="sys.cpu.nice",tags={"host": host,"dc": "lga"})
        reference = {'tsuid': tsuid, 'metric': 'sys.cpu.nice', 'tags': {'host': host, 'dc': 'lga'}}
        self.assertIn(reference,r["results"])

    def test_query(self):
        if self.version != 2: self.skipTest("No server running")
        # prepare some data
        host = self.getUniqueString()
        ts = OpenTSDBTimeSeries("sys.cpu.nice",{"host": host,"dc": "lga"})
        ts.assign_uid(self.client) # make sure that the time series is known
        try:
            tsuid = self.client.set_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)["tsuid"] #get the tsuid - could be done via the OpenTSDBTimeSeries class
        except OpenTSDBError: # this may happen if the TS meta already exists from a previous aborted test.
            tsuid = self.client.get_tsmeta(metric="sys.cpu.nice{host=%s,dc=lga}"%host)[0]["tsuid"]
        meas = [OpenTSDBMeasurement(ts,int(time.time())-200+i,random.random()) for i in range(0,100)]
        response = self.client.put_measurements(meas, compress=True) 
        time.sleep(5)

        # prepare a query
        subquery = OpenTSDBtsuidSubQuery("sum",[tsuid])
        theQuery = OpenTSDBQuery([subquery],'1h-ago',showTSUIDs=True, showSummary=True, showQuery=True)
        # run!
        r = self.client.query(theQuery)
        results = r[0]["dps"]
        # test
        for m in meas: 
            self.assertIn(str(m.timestamp),results)
            self.assertTrue(float(results.get(str(m.timestamp),0))-m.value<1e-6)

        # repeat with a metric query
        filters = [OpenTSDBFilter("literal_or","host",host),OpenTSDBFilter("literal_or","dc","lga")]
        subquery = OpenTSDBMetricSubQuery("sum","sys.cpu.nice",filters=filters)
        theQuery = OpenTSDBQuery([subquery],'1h-ago',showTSUIDs=True, showSummary=True, showQuery=True)
        r2 = self.client.query(theQuery)
        results2 = r[0]["dps"]
        self.assertEqual(results,results2)

        ## repeat with an exp query 
        timeSection = OpenTSDBExpQuery.timeSection("sum", "1h-ago")
        filters = [OpenTSDBExpQuery.filters("id0",[OpenTSDBFilter("literal_or","host",host),OpenTSDBFilter("literal_or","dc","lga")])]
        metrics = [OpenTSDBExpQuery.metric("cpunice","id0","sys.cpu.nice")]
        expressions = [OpenTSDBExpQuery.expression("e1","cpunice*2")]
        outputs = [OpenTSDBExpQuery.output("cpunice","CPU nice"),OpenTSDBExpQuery.output("e1","CPU nice twice")]
        theQuery = OpenTSDBExpQuery(timeSection, filters, metrics, expressions, outputs)
        self.assertRaises(RuntimeError,self.client.query,theQuery) # 2.3 only...
        ## decode and test
        ## NOTE I am experiencing problems with 2.3-RC1... server crash with some basic query. Too early?

        # last query
        querylast = OpenTSDBQueryLast(metrics=[],tsuids=[tsuid],backScan=1,resolveNames=True)
        r = self.client.query(querylast)
        self.assertEqual(r[0]["timestamp"],meas[-1].timestamp*1000)
        self.assertTrue(float(r[0]["value"])-meas[-1].value<1e-6)