blob: 3e42f4c7b31d2eaabcf39b55f2dd48c3dfd5434f [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for multiproduct/model.py"""
import shutil
import sys
import tempfile
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
from sqlite3 import OperationalError
from trac.test import EnvironmentStub
from trac.core import TracError
from trac.ticket.model import Ticket
from multiproduct.env import ProductEnvironment
from multiproduct.model import Product
from bhdashboard.model import ModelBase
from multiproduct.api import MultiProductSystem
from trac.tests.resource import TestResourceChangeListener
class ProductTestCase(unittest.TestCase):
"""Unit tests covering the Product model"""
INITIAL_PREFIX = 'tp'
INITIAL_NAME = 'test project'
INITIAL_DESCRIPTION = 'a test project'
def setUp(self):
self.env = EnvironmentStub(enable=['trac.*', 'multiproduct.*'])
self.env.path = tempfile.mkdtemp('bh-product-tempenv')
self.mpsystem = MultiProductSystem(self.env)
try:
self.mpsystem.upgrade_environment(self.env.db_transaction)
except OperationalError:
# table remains but database version is deleted
pass
self.listener = self._enable_resource_change_listener()
self.default_data = {'prefix':self.INITIAL_PREFIX,
'name':self.INITIAL_NAME,
'description':self.INITIAL_DESCRIPTION}
self.global_env = self.env
self.product = Product(self.env)
self.product._data.update(self.default_data)
self.product.insert()
def tearDown(self):
shutil.rmtree(self.env.path)
self.env.reset_db()
def _enable_resource_change_listener(self):
listener = TestResourceChangeListener(self.env)
listener.resource_type = Product
listener.callback = self.listener_callback
return listener
def listener_callback(self, action, resource, context, old_values = None):
# pylint: disable=unused-argument
# pylint: disable=attribute-defined-outside-init
self.prefix = resource.prefix
self.name = resource.name
self.description = resource.description
def test_set_table_field(self):
"""tests that table.field style update works"""
test = {'prefix': 'td',
'name': 'test field access',
'description': 'product to test field setting'}
product = Product(self.env)
# attempt to set the fields from the data
product.prefix = test['prefix']
product.name = test['name']
product.description = test['description']
self.assertEqual(product._data['prefix'], test['prefix'])
self.assertEqual(product._data['name'], test['name'])
self.assertEqual(product._data['description'], test['description'])
def test_select(self):
"""tests that select can search Products by fields"""
p2_data = {'prefix':'tp2',
'name':'test project 2',
'description':'a different test project'}
p3_data = {'prefix':'tp3',
'name':'test project 3',
'description':'test project'}
product2 = Product(self.env)
product2._data.update(p2_data)
product3 = Product(self.env)
product3._data.update(p3_data)
product2.insert()
product3.insert()
products = list(Product.select(self.env, where={'prefix':'tp'}))
self.assertEqual(1, len(products))
products = list(Product.select(self.env,
where={'name':'test project'}))
self.assertEqual(1, len(products))
products = list(Product.select(self.env,
where={'prefix':'tp3', 'name':'test project 3'}))
self.assertEqual(1, len(products))
def test_update(self):
"""tests that we can use update to push data to the database"""
product = list(Product.select(self.env, where={'prefix':'tp'}))[0]
self.assertEqual('test project', product._data['name'])
new_data = {'prefix':'tp',
'name':'updated',
'description':'nothing'}
product._data.update(new_data)
product.update()
comp_product = list(Product.select(self.env, where={'prefix':'tp'}))[0]
self.assertEqual('updated', comp_product._data['name'])
def test_update_key_change(self):
"""tests that we raise an error for attempting to update key fields"""
bad_data = {'prefix':'tp0',
'name':'update',
'description':'nothing'}
product = list(Product.select(self.env, where={'prefix':'tp'}))[0]
product._data.update(bad_data)
self.assertRaises(TracError, product.update)
def test_insert(self):
"""test saving new Product"""
data = {'prefix':'new', 'name':'new', 'description':'new'}
product = Product(self.env)
product._data.update(data)
product.insert()
check_products = list(Product.select(self.env, where={'prefix':'new'}))
self.assertEqual(product._data['prefix'],
check_products[0]._data['prefix'])
self.assertEqual(1, len(check_products))
def test_insert_duplicate_key(self):
"""test attempted saving of Product with existing key fails"""
dupe_key_data = {'prefix':'tp',
'name':'dupe',
'description':'dupe primary key'}
product2 = Product(self.env)
product2._data.update(dupe_key_data)
self.assertRaises(TracError, product2.insert)
def test_delete(self):
"""test that we are able to delete Products"""
product = list(Product.select(self.env, where={'prefix':'tp'}))[0]
product.delete()
post = list(Product.select(self.env, where={'prefix':'tp'}))
self.assertEqual(0, len(post))
def test_delete_twice(self):
"""test that we error when deleting twice on the same key"""
product = list(Product.select(self.env, where={'prefix':'tp'}))[0]
product.delete()
self.assertRaises(TracError, product.delete)
def test_field_data_get(self):
"""tests that we can use table.field syntax to get to the field data"""
prefix = self.default_data['prefix']
name = self.default_data['name']
description = self.default_data['description']
product = list(Product.select(self.env, where={'prefix':prefix}))[0]
self.assertEqual(prefix, product.prefix)
self.assertEqual(name, product.name)
self.assertEqual(description, product.description)
def test_field_set(self):
"""tests that we can use table.field = something to set field data"""
prefix = self.default_data['prefix']
product = list(Product.select(self.env, where={'prefix':prefix}))[0]
new_description = 'test change of description'
product.description = new_description
self.assertEqual(new_description, product.description)
def test_missing_unique_fields(self):
"""ensure that that insert method works when _meta does not specify
unique fields when inserting more than one ProductResourceMap instances
"""
class TestModel(ModelBase):
"""A test model with no unique_fields"""
_meta = {'table_name': 'bloodhound_testmodel',
'object_name': 'TestModelObject',
'key_fields': ['id',],
'non_key_fields': ['value'],
'unique_fields': [],}
from trac.db import DatabaseManager
schema = [TestModel._get_schema(), ]
with self.env.db_transaction as db:
db_connector, dummy = DatabaseManager(self.env)._get_connector()
for table in schema:
for statement in db_connector.to_sql(table):
db(statement)
structure = dict([(table.name, [col.name for col in table.columns])
for table in schema])
tm1 = TestModel(self.env)
tm1._data.update({'id':1, 'value':'value1'})
tm1.insert()
tm2 = TestModel(self.env)
tm2._data.update({'id':2, 'value':'value2'})
tm2.insert()
def test_change_listener_created(self):
self.assertEqual('created', self.listener.action)
self.assertIsInstance(self.listener.resource, Product)
self.assertEqual(self.INITIAL_PREFIX, self.prefix)
self.assertEqual(self.INITIAL_NAME, self.name)
self.assertEqual(self.INITIAL_DESCRIPTION, self.description)
def test_change_listener_changed(self):
CHANGED_NAME = "changed name"
self.product.name = CHANGED_NAME
self.product.update()
self.assertEqual('changed', self.listener.action)
self.assertIsInstance(self.listener.resource, Product)
self.assertEqual(CHANGED_NAME, self.name)
self.assertEqual({"name":self.INITIAL_NAME}, self.listener.old_values)
def test_change_listener_deleted(self):
self.product.delete()
self.assertEqual('deleted', self.listener.action)
self.assertIsInstance(self.listener.resource, Product)
self.assertEqual(self.INITIAL_PREFIX, self.prefix)
def test_get_tickets(self):
for pdata in (
{'prefix': 'p2', 'name':'product, too', 'description': ''},
{'prefix': 'p3', 'name':'strike three', 'description': ''},
):
num_tickets = 5
product = Product(self.global_env)
product._data.update(pdata)
product.insert()
self.env = ProductEnvironment(self.global_env, product)
for i in range(num_tickets):
ticket = Ticket(self.env)
ticket['summary'] = 'hello ticket #%s-%d' % (product.prefix, i)
ticket['reporter'] = 'admin'
tid = ticket.insert()
# retrieve tickets using both global and product scope
tickets_from_global = [(t['product'], t['id']) for t in
Product.get_tickets(self.global_env, product.prefix)]
self.assertEqual(len(tickets_from_global), num_tickets)
tickets_from_product = [(t['product'], t['id']) for t in
Product.get_tickets(self.env)]
self.assertEqual(len(tickets_from_product), num_tickets)
# both lists should contain same elements
intersection = set(tickets_from_global) & set(tickets_from_product)
self.assertEqual(len(intersection), num_tickets)
def suite():
test_suite = unittest.TestSuite()
test_suite.addTest(unittest.makeSuite(ProductTestCase, 'test'))
return test_suite
if __name__ == '__main__':
unittest.main()