# Copyright 2014 Tesora Inc.
# All Rights Reserved.
#
# Licensed 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 database migration scripts for mysql. To run the tests, you'll need to set up db user named 'openstack_citest'
with password 'openstack_citest' on localhost. This user needs db
admin rights (i.e. create/drop database) """
import glob
import os import migrate.versioning.api as migration_api
from migrate.versioning import repository
from oslo_concurrency import processutils
from oslo_log import log as logging
from proboscis import after_class
from proboscis.asserts import assert_equal
from proboscis.asserts import assert_true
from proboscis import before_class
from proboscis import SkipTest
from proboscis import test
import sqlalchemy
import sqlalchemy.exc from trove.common.i18n import _
import trove.db.sqlalchemy.migrate_repo
from trove.tests.util import event_simulator GROUP = "dbaas.db.migrations"
LOG = logging.getLogger(__name__) @test(groups=[GROUP])
class ProjectTestCase(object):
"""Test migration scripts integrity.""" @test
def test_all_migrations_have_downgrade(self):
topdir = os.path.normpath(os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir))
py_glob = os.path.join(topdir, "trove", "db", "sqlalchemy",
"migrate_repo", "versions", "*.py") missing_downgrade = []
for path in glob.iglob(py_glob):
has_upgrade = False
has_downgrade = False
with open(path, "r") as f:
for line in f:
if 'def upgrade(' in line:
has_upgrade = True
if 'def downgrade(' in line:
has_downgrade = True if has_upgrade and not has_downgrade:
fname = os.path.basename(path)
missing_downgrade.append(fname) helpful_msg = (_("The following migration scripts are missing a "
"downgrade implementation:\n\t%s") %
'\n\t'.join(sorted(missing_downgrade)))
assert_true(not missing_downgrade, helpful_msg) @test(depends_on_classes=[ProjectTestCase],
groups=[GROUP])
class TestTroveMigrations(object):
"""Test sqlalchemy-migrate migrations."""
USER = "openstack_citest"
PASSWD = "openstack_citest"
DATABASE = "openstack_citest" @before_class
def setUp(self):
event_simulator.allowable_empty_sleeps = 1 @after_class
def tearDown(self):
event_simulator.allowable_empty_sleeps = 0 def __init__(self):
self.MIGRATE_FILE = trove.db.sqlalchemy.migrate_repo.__file__
self.REPOSITORY = repository.Repository(
os.path.abspath(os.path.dirname(self.MIGRATE_FILE)))
self.INIT_VERSION = 0 def _get_connect_string(self, backend, database=None):
"""Get database connection string."""
args = {'backend': backend,
'user': self.USER,
'passwd': self.PASSWD}
template = "%(backend)s://%(user)s:%(passwd)s@localhost"
if database is not None:
args['database'] = database
template += "/%(database)s"
return template % args def _is_backend_avail(self, backend):
"""Check database backend availability."""
connect_uri = self._get_connect_string(backend)
engine = sqlalchemy.create_engine(connect_uri)
try:
connection = engine.connect()
except Exception:
# any error here means the database backend is not available
return False
else:
connection.close()
return True
finally:
if engine is not None:
engine.dispose() def _execute_cmd(self, cmd=None):
"""Shell out and run the given command."""
out, err = processutils.trycmd(cmd, shell=True)
# Until someone wants to rewrite this to avoid the warning
# we need to handle it for newer versions of mysql
valid_err = err == '' or \
err == 'mysql: [Warning] Using a password on the ' \
'command line interface can be insecure.\n'
assert_true(valid_err,
"Failed to run: '%(cmd)s' "
"Output: '%(stdout)s' "
"Error: '%(stderr)s'" %
{'cmd': cmd, 'stdout': out, 'stderr': err}) def _reset_mysql(self):
"""Reset the MySQL test database Drop the MySQL test database if it already exists and create
a new one.
"""
sql = ("drop database if exists %(database)s; "
"create database %(database)s;" % {'database': self.DATABASE})
cmd = ("mysql -u \"%(user)s\" -p%(password)s -h %(host)s "
"-e \"%(sql)s\"" % {'user': self.USER, 'password': self.PASSWD,
'host': 'localhost', 'sql': sql})
self._execute_cmd(cmd) @test
def test_mysql_migration(self):
db_backend = "mysql+pymysql"
# Gracefully skip this test if the developer do not have
# MySQL running. MySQL should always be available on
# the infrastructure
if not self._is_backend_avail(db_backend):
raise SkipTest("MySQL is not available.")
self._reset_mysql()
connect_string = self._get_connect_string(db_backend, self.DATABASE)
engine = sqlalchemy.create_engine(connect_string)
self._walk_versions(engine)
engine.dispose() def _walk_versions(self, engine=None): //跑版本
"""Walk through and test the migration scripts Determine latest version script from the repo, then
upgrade from 1 through to the latest, then downgrade from
the latest back to 1, with no data in the databases. This
just checks that the schema itself upgrades and downgrades
successfully.
"""
# Place the database under version control
migration_api.version_control(engine, self.REPOSITORY,
self.INIT_VERSION)
assert_equal(self.INIT_VERSION,
migration_api.db_version(engine, self.REPOSITORY)) LOG.debug('Latest version is %s' % self.REPOSITORY.latest)
versions = range(self.INIT_VERSION + 1, self.REPOSITORY.latest + 1) //从最开始的那版跑到最新那版+1终止,INIT_VERSION初始值是0,所以要+ 1,range函数的终止是后面那个参数,但不会到那个参数,相当于++i # Snake walk from version 1 to the latest, testing the upgrade paths.
# upgrade -> downgrade -> upgrade
for version in versions:
self._migrate_up(engine, version)
self._migrate_down(engine, version - 1)
self._migrate_up(engine, version) # Now snake walk back down to version 1 from the latest, testing the
# downgrade paths.
# downgrade -> upgrade -> downgrade
for version in reversed(versions):
self._migrate_down(engine, version - 1)
self._migrate_up(engine, version)
self._migrate_down(engine, version - 1) def _migrate_down(self, engine, version):                                  //版本往上跑
"""Migrate down to an old version of database."""
migration_api.downgrade(engine, self.REPOSITORY, version)
assert_equal(version,
migration_api.db_version(engine, self.REPOSITORY)) def _migrate_up(self, engine, version): //版本往下跑
"""Migrate up to a new version of database."""
migration_api.upgrade(engine, self.REPOSITORY, version)
assert_equal(version,
migration_api.db_version(engine, self.REPOSITORY)) 这个文件感觉大部分就是在做版本的问题,看看升级版本或者降级版本的时候,数据是不是会被破坏,我是这么理解的。。。

trove,测试,db小解析的更多相关文章

  1. 屠龙之路_击败DB小boss_FifthDay

    摘要:服务器大魔王被击败的消息传到了恶龙boss那里,恶龙大怒派出了自己的首级大将DB人称小boss,但小boss的名号并没有吓到七位屠龙勇士,经过他们齐心协力的进攻,最终击败了DB,小boss临死前 ...

  2. 使用Appium 测试微信小程序和微信公众号方法

    由于腾讯系QQ.微信等都是基于腾讯自研X5内核,不是google原生webview,需要打开TBS内核Inspector调试功能才能用Chrome浏览器查看页面元素,并实现Appium自动化测试微信小 ...

  3. Appium之测试微信小程序

    坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:Oschina.云+社区.知乎等各大平台都有. 目录 一.往期回顾 二.测试微信小程序 1.准备工作 2.操作步骤 3.注意 4.强制设置安卓的进程 ...

  4. ESA2GJK1DH1K微信小程序篇: 测试微信小程序APUConfig给WI-Fi模块配网并绑定设备,并通过MQTT控制设备

    前言(源码使用介绍在最后) 一,微信小程序篇小程序下载(该源码为这节测试源代码) 二.有多少人一直在期盼着小程序可以实现SmartConfig或者Airkiss的功能? 来吧!我的这种方式包您满意. ...

  5. Miller-Rabin素数测试学习小计

    1.Miller-Rabin是干啥的?它是用来检测一个数字(一般是很大的数字)是不是素数: 2.Miller-Rabin算法基于的两个定理: (1)费尔马小定理:如果p是一个素数,且0<a< ...

  6. fastJson解析复杂的json字符串,经测试已经成功解析

    要解析的json数据格式为: HTTP/1.1 200 OK Content-Type: text/jsv Content-Length: length { ResponseStatus: { }, ...

  7. 自己动手编写IPv4地址包含关系测试的小脚本

    工作中需要对地址包含关系进行测试,现有ipaddress标准库和IPy无法满足,于是自己动手编写小脚本,主要实现== , in, <等专用功能,其他功能可以后续用到再补充,例如迭代打印网段内所有 ...

  8. java对象传递小解析

    先上代码: import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder ...

  9. Web进行压力测试的小工具

    在Linux下对Web进行压力测试的小工具有很多,比较出名的有AB.虽然AB可以运行在windows下,但对于想简单界面操作的朋友有点不太习惯.其实vs.net也提供压力测试功能但显然显得太重了,在测 ...

随机推荐

  1. 关于ADB server didn't ACK * failed to start daemon *的问题

    查看5037端口被谁占用了, 开始--运行--CMD 到命令提示符,输入 netstat -aon|findstr "5037" 输入 tasklist|findstr " ...

  2. canvas 之刮刮卡

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 鸟哥的LINUX私房菜基础篇第三版 阅读笔记 一

    1. Linux的档案权限与目录配置      一.基础知识:             a.分为三类,拥有者(owner).群组(group).其他人(other)             b.三个核 ...

  4. 数据访问模式之Repository模式

    数据访问模式之Repository模式   数据访问层无非就是对数据进行增删改查,其中增.删.改等我们可以抽象出来写一个公共的接口或抽象类来定义这些方法,并采用一个基类实现这些方法,这样该基类派生的子 ...

  5. 自定义html标签

    自定义html标签 (觉得页面全是div 的解决办法 来个个性化) 办法一(来源于 让ie支持html5标签的方法): 在ie9以前如果要自定义要使用document.createElement的方法 ...

  6. 用django创建一个简单的sns

    用django创建一个简单的sns 1.首先创建一个工程newsns django-admin.py startproject newsns 在工程目录下新建一个文件夹templates,在该文件夹下 ...

  7. 大数据应用之Windows平台Hbase客户端Eclipse开发环境搭建

    大数据应用之Windows平台Hbase客户端Eclipse开发环境搭建 大数据应用之Windows平台Hbase客户端Eclipse环境搭建-Java版 作者:张子良 版权所有,转载请注明出处 引子 ...

  8. HDU 2073 无限的路

    Problem Description 甜甜从小就喜欢画图画,最近他买了一支智能画笔,由于刚刚接触,所以甜甜只会用它来画直线,于是他就在平面直角坐标系中画出如下的图形: 甜甜的好朋友蜜蜜发现上面的图还 ...

  9. Exchange Server 2013 一步步安装图解[完全步骤截图]

    前言: 这是一份为Exchange菜鸟准备的2013版本安装文档,安装环境为Windows Server 2012 DataCenter 版本,在安装之前,我对安装Exchange也是处于一无所知的状 ...

  10. SVN插件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...