This commit is contained in:
Jonathan Eads 2013-04-25 16:13:06 -07:00
Родитель 882ce71b0f 6d43a2fccb
Коммит eaccfecd00
13 изменённых файлов: 794 добавлений и 32 удалений

Просмотреть файл

@ -98,3 +98,26 @@ def sample_data():
"""Returns a SampleData() object"""
from sampledata import SampleData
return SampleData()
@pytest.fixture()
def jobs_ds():
from django.conf import settings
from treeherder.model.models import Datasource
return Datasource.objects.create(
project=settings.DATABASES["default"]["TEST_NAME"],
dataset=1,
contenttype="jobs",
host="localhost",
)
@pytest.fixture()
def objectstore_ds():
from django.conf import settings
from treeherder.model.models import Datasource
return Datasource.objects.create(
project=settings.DATABASES["default"]["TEST_NAME"],
dataset=1,
contenttype="objectstore",
host="localhost",
)

0
tests/model/__init__.py Normal file
Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,168 @@
import os
import pytest
from django.conf import settings
from treeherder.model.derived import RefDataManager
from datasource.bases.BaseHub import BaseHub
from treeherder.model.models import RepositoryGroup, Repository
@pytest.fixture(scope="module")
def refdata():
"""returns a patched RefDataManager for testing purpose"""
refdata = RefDataManager()
#make the test procs available to RefDataManager
del BaseHub.procs['reference']
refdata.dhub.data_sources['reference']["procs"].append(
os.path.join(
os.path.abspath(os.path.dirname(__file__)),
"refdata_test.json"
)
)
refdata.dhub.load_procs('reference')
return refdata
@pytest.fixture(scope="module")
def repository_id():
repo_group = RepositoryGroup(
name='mygroup',
description='fill me',
active_status='active'
)
repo_group.save()
repo = Repository.objects.create(
repository_group=repo_group,
name='myrepo',
type='git',
url='https://github.com/mozilla/treeherder-service.git',
branch='mybranch',
project_name='myproject',
purpose='development',
active_status='active'
)
return repo.id
test_params = [
{
'func': 'get_or_create_build_platform',
'input': ['linux', 'Fedora 12', 'x86_64'],
'test_proc': 'refdata_test.selects.test_build_platform',
'expected': [{
'os_name': 'linux',
'platform': 'Fedora 12',
'architecture': 'x86_64',
'active_status': 'active'
}]
},
{
'func': 'get_or_create_job_group',
'input': ['mygroup'],
'test_proc': 'refdata_test.selects.test_job_group',
'expected': [{
'symbol': 'fill me',
'name': 'mygroup',
'description': 'fill me',
'active_status': 'active'
}]
},
{
'input': ['myname', 'mygroup'],
'func': 'get_or_create_job_type',
'test_proc': 'refdata_test.selects.test_job_type',
'expected': [{
'symbol': 'fill me',
'name': 'myname',
'group': 'mygroup',
'description': 'fill me',
'active_status': 'active'
}]
},
{
'input': ['myname', 1366290144.07455],
'func': 'get_or_create_machine',
'test_proc': 'refdata_test.selects.test_machine',
'expected': [{
'name': 'myname',
'first_timestamp': 1366290144,
'last_timestamp': 1366290144,
'active_status': 'active'
}]
},
{
'func': 'get_or_create_machine_platform',
'input': ['linux', 'Fedora 12', 'x86_64'],
'test_proc': 'refdata_test.selects.test_machine_platform',
'expected': [{
'os_name': 'linux',
'platform': 'Fedora 12',
'architecture': 'x86_64',
'active_status': 'active'
}]
},
{
'func': 'get_or_create_option',
'input': ['myoption'],
'test_proc': 'refdata_test.selects.test_option',
'expected': [{
'name': 'myoption',
'description': 'fill me',
'active_status': 'active'
}]
},
{
'func': 'get_or_create_option_collection',
'input': [['option1', 'option2']],
'test_proc': 'refdata_test.selects.test_option_collection',
'expected': [{'name': 'option1'}, {'name': 'option2'}]
},
{
'func': 'get_or_create_product',
'input': ['myproduct'],
'test_proc': 'refdata_test.selects.test_product',
'expected': [{
'name': 'myproduct',
'description': 'fill me',
'active_status': 'active'
}]
}
]
@pytest.mark.parametrize(("params"), test_params)
def test_refdata_manager(refdata, params):
"""test get_or_create methods produce the right content"""
#call the right refdata method based on params
id = getattr(refdata, params['func'])(*params['input'])
row_data = refdata.dhub.execute(
proc=params["test_proc"],
placeholders=[id]
)
for i, row in enumerate(row_data):
for k, v in params['expected'][i].items():
assert row[k] == v
# some tests just don't fit into the standard layout
# def test_repository_version_creation(refdata, repository_id):
# id = refdata.get_or_create_repository_version(
# repository_id,
# 'v1',
# 1366290144.07455)
# row_data = refdata.dhub.execute(
# proc=params[refdata_test.selects.test_repository_version],
# placeholders=[id]
# )[0]
# assert row[repository_id] == 1
# assert row[version] == 'v1'
# assert row[version_timestamp] == 1366290144
# assert row[active_status] == 'active'

Просмотреть файл

@ -0,0 +1,79 @@
{
"inserts":{},
"selects":{
"test_build_platform":{
"sql": "SELECT `platform`, `os_name`, `architecture`, `active_status`
FROM `build_platform`
WHERE
`id` = ?",
"host":"read_host"
},
"test_job_group":{
"sql": "SELECT `symbol`, `name`, `description`, `active_status`
FROM `job_group`
WHERE
`id` = ?",
"host":"read_host"
},
"test_job_type":{
"sql": "SELECT
jg.name AS 'group',
jt.`symbol`,
jt.`name`,
jt.`description`,
jt.`active_status`
FROM `job_type` jt
INNER JOIN `job_group` jg
on jg.id = jt.job_group_id
WHERE
jt.`id` = ?",
"host":"read_host"
},
"test_machine":{
"sql": "SELECT `name`, `first_timestamp`, `last_timestamp`, `active_status`
FROM `machine`
WHERE
`id` = ?",
"host":"read_host"
},
"test_machine_platform":{
"sql": "SELECT `platform`, `os_name`, `architecture`, `active_status`
FROM `machine_platform`
WHERE
`id` = ?",
"host":"read_host"
},
"test_option":{
"sql": "SELECT `name`, `description`, `active_status`
FROM `option`
WHERE
`id` = ?",
"host":"read_host"
},
"test_option_collection":{
"sql": "SELECT o.`name`
FROM `option` o
INNER JOIN `option_collection` oc
ON o.`id` = oc.`option_id`
WHERE
oc.`id` = ?
ORDER BY o.`name`",
"host":"read_host"
},
"test_product":{
"sql": "SELECT `name`, `description`, `active_status`
FROM `product`
WHERE
`id` = ?",
"host":"read_host"
},
"test_repository_version":{
"sql": "SELECT `repository_id`, `version`, `version_timestamp`, `active_status`
FROM `repository_version`
WHERE
`id` = ?",
"host":"read_host"
}
}
}

Просмотреть файл

Просмотреть файл

@ -5,28 +5,6 @@ import MySQLdb
from django.core.cache import cache
@pytest.fixture
def jobs_ds():
prefix = getattr(settings, "TEST_DB_PREFIX", "")
return Datasource.objects.create(
project="{0}test_myproject".format(prefix),
dataset=1,
contenttype="jobs",
host="localhost",
)
@pytest.fixture
def objectstore_ds():
prefix = getattr(settings, "TEST_DB_PREFIX", "")
return Datasource.objects.create(
project="{0}test_myproject".format(prefix),
dataset=1,
contenttype="objectstore",
host="localhost",
)
@pytest.fixture
def db_conn():
return MySQLdb.connect(

Просмотреть файл

@ -0,0 +1,2 @@
from .base import *
from .refdata import *

Просмотреть файл

@ -0,0 +1,33 @@
"""
``TreeHerderModelBase`` (and subclasses) are the public interface for all data
access.
"""
from django.conf import settings
from treeherder.model.sql.datasource import SQLDataSource
class TreeherderModelBase(object):
"""Base model class for all TreeHerder models"""
def __init__(self, project):
self.project = project
self.sources = {}
for ct in self.CONTENT_TYPES:
self.sources[ct] = SQLDataSource(project, ct)
self.DEBUG = settings.DEBUG
def __unicode__(self):
"""Unicode representation is project name."""
return self.project
def disconnect(self):
"""Iterate over and disconnect all data sources."""
for src in self.sources.itervalues():
src.disconnect()
def get_project_cache_key(self, str_data):
return "{0}_{1}".format(self.project, str_data)

Просмотреть файл

@ -0,0 +1,276 @@
import os
from django.conf import settings
from datasource.bases.BaseHub import BaseHub
from datasource.DataHub import DataHub
from .base import TreeherderModelBase
class RefDataManager(object):
"""Model for reference data"""
def __init__(self):
procs_path = os.path.join(os.path.dirname(os.path.dirname(__file__)),
'sql', 'reference.json')
data_source = {
'reference': {
"hub": "MySQL",
"master_host": {
"host": settings.DATABASES['default']['HOST'],
"user": settings.DATABASES['default']['USER'],
"passwd": settings.DATABASES['default']['PASSWORD']
},
"default_db": settings.DATABASES['default']['NAME'],
"procs": [procs_path]
}
}
BaseHub.add_data_source(data_source)
self.dhub = DataHub.get("reference")
self.DEBUG = settings.DEBUG
def get_build_platform_id(self, os_name, platform, architecture):
id_iter = self.dhub.execute(
proc='reference.selects.get_build_platform_id',
placeholders=[os_name, platform, architecture],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_build_platform(self, os_name, platform, architecture):
self.dhub.execute(
proc='reference.inserts.create_build_platform',
placeholders=[
os_name,
platform,
architecture,
os_name,
platform,
architecture,
],
debug_show=self.DEBUG)
return self.get_build_platform_id(
os_name,
platform,
architecture)
def get_job_group_id(self, name):
id_iter = self.dhub.execute(
proc='reference.selects.get_job_group_id',
placeholders=[name],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_job_group(self, name):
self.dhub.execute(
proc='reference.inserts.create_job_group',
placeholders=[
name,
name
],
debug_show=self.DEBUG)
return self.get_job_group_id(name)
def get_job_type_id(self, name, group):
id_iter = self.dhub.execute(
proc='reference.selects.get_job_type_id',
placeholders=[name, group],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_job_type(self, name, group):
group_id = self.get_or_create_job_group(group)
self.dhub.execute(
proc='reference.inserts.create_job_type',
placeholders=[
group_id,
name,
group_id,
name
],
debug_show=self.DEBUG)
return self.get_job_type_id(name, group)
def get_machine_id(self, name):
id_iter = self.dhub.execute(
proc='reference.selects.get_machine_id',
placeholders=[name],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_machine(self, name, timestamp):
self.dhub.execute(
proc='reference.inserts.create_machine',
placeholders=[
name,
timestamp,
timestamp,
name
],
debug_show=self.DEBUG)
return self.get_machine_id(name)
def get_machine_platform_id(self, os_name, platform, architecture):
id_iter = self.dhub.execute(
proc='reference.selects.get_machine_platform_id',
placeholders=[os_name, platform, architecture],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_machine_platform(self, os_name, platform,
architecture):
self.dhub.execute(
proc='reference.inserts.create_machine_platform',
placeholders=[
os_name,
platform,
architecture,
os_name,
platform,
architecture,
],
debug_show=self.DEBUG)
return self.get_machine_platform_id(
os_name,
platform,
architecture)
def get_option_id(self, name):
id_iter = self.dhub.execute(
proc='reference.selects.get_option_id',
placeholders=[name],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_option(self, name):
self.dhub.execute(
proc='reference.inserts.create_option',
placeholders=[
name,
name
],
debug_show=self.DEBUG)
return self.get_option_id(name)
def get_option_collection_id(self, options):
"""returns an option_collection_id given a list of options"""
options = sorted(list(options))
id_iter = self.dhub.execute(
proc='reference.selects.get_option_collection_id',
placeholders=[','.join(options)],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('option_collection_id')
def get_max_collection_id(self):
"""returns the max collection id available"""
max_id = self.dhub.execute(
proc='reference.selects.get_max_collection_id',
placeholders=[],
debug_show=self.DEBUG,
return_type='tuple')
return max_id[0]['max_id'] or 0
def get_or_create_option_collection(self, options):
#check if this collection already exists
id = self.get_option_collection_id(options)
if not id:
#retrieve the last collection
option_collection_id = self.get_max_collection_id() + 1
for option in options:
#create an option if it doesn't exist
option_id = self.get_or_create_option(option)
# create an entry in option_collection
self.dhub.execute(
proc='reference.inserts.create_option_collection',
placeholders=[
option_collection_id,
option_id,
option_collection_id,
option_id
],
debug_show=self.DEBUG)
id = self.get_option_collection_id(options)
return id
def get_product_id(self, name):
id_iter = self.dhub.execute(
proc='reference.selects.get_product_id',
placeholders=[name],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_product(self, name):
self.dhub.execute(
proc='reference.inserts.create_product',
placeholders=[
name,
name
],
debug_show=self.DEBUG)
return self.get_product_id(name)
def get_repository_version(self, repository_id, version):
id_iter = self.dhub.execute(
proc='reference.selects.get_repository_version_id',
placeholders=[name],
debug_show=self.DEBUG,
return_type='iter')
return id_iter.get_column_data('id')
def get_or_create_repository_version(self, repository_id, version,
version_timestamp):
self.dhub.execute(
proc='reference.inserts.create_repository_version',
placeholders=[
repository_id,
version,
version_timestamp,
repository_id,
version
],
debug_show=self.DEBUG)
return self.get_repository_version(repository_id, version)

Просмотреть файл

@ -4,12 +4,16 @@ import subprocess
import os
from django.core.cache import cache
from django.db import models
from django.conf import settings
from datasource.bases.BaseHub import BaseHub
from datasource.hubs.MySQL import MySQL
from treeherder import path
# the cache key is specific to the database name we're pulling the data from
SOURCES_CACHE_KEY = "treeherder-datasources"
SQL_PATH = os.path.dirname(os.path.abspath(__file__))
SQL_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sql')
class Product(models.Model):
@ -199,7 +203,7 @@ class Datasource(models.Model):
inserting = not self.pk
# in case you want to add a new datasource and provide
# a pk, set force_insert=True when you save
if inserting or kwargs.get('force_insert',False):
if inserting or kwargs.get('force_insert', False):
if not self.name:
self.name = "{0}_{1}_{2}".format(
self.project,
@ -244,21 +248,21 @@ class Datasource(models.Model):
"host": self.host,
"user": settings.TREEHERDER_DATABASE_USER,
"passwd": settings.TREEHERDER_DATABASE_PASSWORD,
},
},
"default_db": self.name,
"procs": [
os.path.join(SQL_PATH, procs_file_name),
os.path.join(SQL_PATH, "generic.json"),
],
}
],
}
}
if self.read_only_host:
data_source[self.key]['read_host'] = {
"host": self.read_only_host,
"user": settings.TREEHERDER_RO_DATABASE_USER,
"passwd": settings.TREEHERDER_RO_DATABASE_PASSWORD,
}
}
BaseHub.add_data_source(data_source)
# @@@ the datahub class should depend on self.type

Просмотреть файл

@ -7,12 +7,9 @@ import os
import subprocess
import uuid
from datasource.bases.BaseHub import BaseHub
from datasource.hubs.MySQL import MySQL
from django.conf import settings
from django.core.cache import cache
from django.db import models, transaction
import MySQLdb
from treeherder.model.models import Datasource
@ -68,7 +65,7 @@ class SQLDataSource(object):
def _get_datasource(self):
candidate_sources = []
for source in DataSource.objects.cached():
for source in Datasource.objects.cached():
if (source.project == self.project and
source.contenttype == self.contenttype):
candidate_sources.append(source)

Просмотреть файл

@ -0,0 +1,202 @@
{
"inserts":{
"create_build_platform":{
"sql": "INSERT INTO `build_platform` (`os_name`, `platform`, `architecture`, `active_status`)
SELECT ?, ?, ?, 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `os_name`, `platform`, `architecture`
FROM `build_platform`
WHERE `os_name` = ? AND `platform` = ? AND `architecture` = ?
)",
"host":"master_host"
},
"create_job_group":{
"sql":"INSERT INTO `job_group` (`symbol`, `name`, `description`, `active_status`)
SELECT 'fill me', ?, 'fill me', 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `name`
FROM `job_group`
WHERE `name` = ?
)",
"host":"master_host"
},
"create_job_type":{
"sql":"INSERT INTO `job_type` (`job_group_id`, `symbol`, `name`, `description`, `active_status`)
SELECT ?, 'fill me', ?, 'fill me', 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `name`
FROM `job_type`
WHERE `job_group_id` = ? and `name` = ?
)",
"host":"master_host"
},
"create_machine" : {
"sql": "INSERT INTO `machine` (`name`, `first_timestamp`, `last_timestamp`, `active_status`)
SELECT ?, ?, ?, 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `name`
FROM `machine`
WHERE `name` = ?
)
ON DUPLICATE KEY UPDATE `last_timestamp` = VALUES(`last_timestamp`)",
"host":"master_host"
},
"create_machine_platform":{
"sql": "INSERT INTO `machine_platform` (`os_name`, `platform`, `architecture`, `active_status`)
SELECT ?, ?, ?, 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `os_name`, `platform`, `architecture`
FROM `machine_platform`
WHERE `os_name` = ? AND `platform` = ? AND `architecture` = ?
)",
"host":"master_host"
},
"create_option":{
"sql":"INSERT INTO `option` (`name`, `description`, `active_status`)
SELECT ?, 'fill me', 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `name`
FROM `option`
WHERE `name` = ?
)",
"host":"master_host"
},
"create_option_collection":{
"sql": "INSERT INTO `option_collection` (`option_collection_id`, `option_id`)
SELECT ?, ?
FROM DUAL
WHERE NOT EXISTS(
SELECT `option_collection_id`, `option_id`
FROM `option_collection`
WHERE `option_collection_id` = ? AND `option_id` = ?
)",
"host":"master_host"
},
"create_product":{
"sql": "INSERT INTO `product` (`name`, `description`, `active_status`)
SELECT ?, 'fill me', 'active'
FROM DUAL
WHERE NOT EXISTS (
SELECT `name`
FROM `product`
WHERE `name` = ?
)",
"host":"master_host"
},
"create_repository_version":{
"sql": "INSERT INTO `repository_version` (`repository_id`, `version`, `version_timestamp`, `active_status`)
SELECT ?, ?, ?, 'active'
FROM DUAL
WHERE NOT EXISTS(
SELECT `repository_id`, `version`
FROM `repository_version`
WHERE `repository_id` = ? AND `version` = ?
)",
"host":"master_host"
}
},
"selects":{
"get_build_platform_id":{
"sql": "SELECT `id`
FROM `build_platform`
WHERE
`os_name` = ?
AND `platform` = ?
AND `architecture` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_job_group_id":{
"sql": "SELECT `id`
FROM `job_group`
WHERE
`name` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_job_type_id":{
"sql": "SELECT jt.`id`
FROM `job_type` jt
INNER JOIN `job_group` jg
ON jg.id = jt.job_group_id
WHERE
jt.`name` = ?
AND jg.`name` = ?
AND jt.`active_status` = 'active'
AND jg.`active_status` = 'active'",
"host":"read_host"
},
"get_machine_id":{
"sql": "SELECT `id`
FROM `machine`
WHERE
`name` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_machine_platform_id":{
"sql": "SELECT `id`
FROM `machine_platform`
WHERE
`os_name` = ?
AND `platform` = ?
AND `architecture` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_option_id":{
"sql": "SELECT `id`
FROM `option`
WHERE
`name` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_max_collection_id":{
"sql": "SELECT MAX(`option_collection_id`) as 'max_id'
FROM `option_collection`",
"host":"read_host"
},
"get_option_collection_id":{
"sql": "SELECT `option_collection_id`
FROM `option_collection` oc
INNER JOIN `option` o on o.id = oc.option_id
GROUP BY `option_collection_id`
HAVING
GROUP_CONCAT(o.name ORDER BY o.name ASC SEPARATOR ',') = ?",
"host":"read_host"
},
"get_product_id":{
"sql": "SELECT `id`
FROM `product`
WHERE
`name` = ?
AND `active_status` = 'active'",
"host":"read_host"
},
"get_repository_version_id":{
"sql": "SELECT `id`
FROM `repository_version`
WHERE
`repository_id` = ?
AND `version` = ?
AND `active_status` = 'active'",
"host":"read_host"
}
}
}