Fix incorrect trait initialization

Currently, when we try to get trait, the api service uses storage
data to directly initialize the trait model. However, the trait class
init method expects value field as wsme.text type, while in storage,
it could be int, float, or datetime. So, end user will get 400 error
in such scenarios.

The static method _convert_storage_trait() in Event class can convert
a storage trait data to api trait object, we can use it to fix this
bug. Also, this method should be in Trait class instead of Event class,
This patch does this refactor too.

Change-Id: Ia7bf667967a31a3cc6e8d457f3b6330ffc728471
Closes-Bug: #1324523
This commit is contained in:
ZhiQiang Fan 2014-06-04 02:10:53 +08:00 committed by ZhiQiang Fan
parent ebfa5ad648
commit 8f3f15b6d1
2 changed files with 27 additions and 18 deletions

View File

@ -2185,6 +2185,19 @@ class Trait(_Base):
type = wtypes.text
"the type of the trait (string, integer, float or datetime)"
@staticmethod
def _convert_storage_trait(trait):
"""Helper method to convert a storage model into an API trait
instance. If an API trait instance is passed in, just return it.
"""
if isinstance(trait, Trait):
return trait
value = (six.text_type(trait.value)
if not trait.dtype == storage.models.Trait.DATETIME_TYPE
else trait.value.isoformat())
trait_type = storage.models.Trait.get_name_by_type(trait.dtype)
return Trait(name=trait.name, type=trait_type, value=value)
@classmethod
def sample(cls):
return cls(name='service',
@ -2207,21 +2220,8 @@ class Event(_Base):
def get_traits(self):
return self._traits
@staticmethod
def _convert_storage_trait(t):
"""Helper method to convert a storage model into an API trait
instance. If an API trait instance is passed in, just return it.
"""
if isinstance(t, Trait):
return t
value = (six.text_type(t.value)
if not t.dtype == storage.models.Trait.DATETIME_TYPE
else t.value.isoformat())
type = storage.models.Trait.get_name_by_type(t.dtype)
return Trait(name=t.name, type=type, value=value)
def set_traits(self, traits):
self._traits = map(self._convert_storage_trait, traits)
self._traits = map(Trait._convert_storage_trait, traits)
traits = wsme.wsproperty(wtypes.ArrayType(Trait),
get_traits,
@ -2293,7 +2293,7 @@ class TraitsController(rest.RestController):
:param trait_name: Trait to return values for
"""
LOG.debug(_("Getting traits for %s") % event_type)
return [Trait(name=t.name, type=t.get_type_name(), value=t.value)
return [Trait._convert_storage_trait(t)
for t in pecan.request.storage_conn
.get_traits(event_type, trait_name)]

View File

@ -94,11 +94,20 @@ class TestTraitAPI(EventTestBase):
def test_get_trait_data_for_event(self):
path = (self.PATH % "Foo") + "/trait_A"
data = self.get_json(path, headers=headers)
self.assertEqual(1, len(data))
self.assertEqual("trait_A", data[0]['name'])
trait = data[0]
self.assertEqual("trait_A", trait['name'])
path = (self.PATH % "Foo") + "/trait_B"
data = self.get_json(path, headers=headers)
self.assertEqual(1, len(data))
self.assertEqual("trait_B", data[0]['name'])
self.assertEqual("1", data[0]['value'])
path = (self.PATH % "Foo") + "/trait_D"
data = self.get_json(path, headers=headers)
self.assertEqual(1, len(data))
self.assertEqual("trait_D", data[0]['name'])
self.assertEqual(self.trait_time.isoformat(), data[0]['value'])
def test_get_trait_data_for_non_existent_event(self):
path = (self.PATH % "NO_SUCH_EVENT") + "/trait_A"