0

我使用行为来运行我们基于小黄瓜的测试套件,并使用一个自定义运行器来处理并行运行行为。

这在我的本地(Windows 8.1)机器上完美运行,并允许我使用 os.environ.update 在我的子进程中更改环境变量

这在我们的 Ubuntu 14.04 服务器上失败,并且无法更改环境变量,这与每个测试运行的数据库名称一致。我正在做的一些剥离代码如下:

def create_database(name):
    #create a postgres database, this works.    
    return "our_test_database_%s" % name

def drop_database(name):
    #drop a postgres database, also works
    return name

def get_features():
    return [feature for feature in os.listdir(features) if feature.endswith(".feature")

def main():
    manager = multiprocessing.Manager()
    databases = manager.Queue()
    cpu_count = multiprocessing.cpu_count()

    for i in range(cpu_count):
        databases.put(create_database(str(i)))

    pool = multiprocessing.Pool(processes=cpu_count, maxtaskperchild=1)
    results = pool.map(run_test, (feature, databases for feature in features), chunksize=1)

    while database = databases.get_nowait():
        drop_database(database)

def run_test(feature, databases):
    database = databases.get(block=True)
    os.environ.update({
        'DATABASE_URL': database
    })

    config = behave.configuration.Configuration(("--no-logcapture", "--tags=~@skip", "-f", "plain", feature))
    runner = behave.runner.Runner(config)
    failed = runner.run()

    databases.put(database)

在行为内部,我们使用数据库来测试我们的 Flask 应用程序。Flask 运行时找不到设置的环境变量。

编辑:我不知道发生了什么变化,我们在服务器和我的机器上使用相同版本的 Python,以及所有已知使用过的软件包的相同版本。环境变量未正确更新,因此无法在以后的代码中访问。

4

2 回答 2

1

好吧,您可以完全避免使用 a multiprocessing.Manager(),通过使用initializer关键字参数 tomultiprocessing.Pool将法线传递multiprocessing.Queue给所有工作人员:

def main():
    databases = multiprocessing.Queue()
    cpu_count = multiprocessing.cpu_count()

    for i in range(cpu_count):
        databases.put(create_database(str(i)))

    pool = multiprocessing.Pool(processes=cpu_count, maxtasksperchild=1, 
                                initializer=init, initargs=(databases,))
    results = pool.map(run_test, features, chunksize=1)

    while database = databases.get_nowait():
        drop_database(database)

def init(dbs):
    global databases
    databases = dbs

def run_test(feature):
    database = databases.get(block=True)  # databases will be defined in the global namespace
    os.environ.update({
        'DATABASE_URL': database
    })

    config = behave.configuration.Configuration(("--no-logcapture", "--tags=~@skip", "-f", "plain", feature))
    runner = behave.runner.Runner(config)
    failed = runner.run()

这并不能真正Manager解决Manager.

于 2014-08-26T01:16:04.033 回答
0

真正的问题出在我的get_features()功能上。

实际使用的代码要复杂一些,并使用behaviour 的试运行来获取我的功能文件中所有未跳过场景的列表。看起来,这次试运行导入了我们的烧瓶应用程序。

在 windows 上, multiprocessing.Process 不与父进程共享 sys.modules 空间,在 linux 上则不是这样。在父进程上下文中导入应用程序时,子进程都在重用该导入和配置的烧瓶应用程序。

这记录在https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods

在 Python3 上, multiprocessing.set_start_method('spawn') 可用于将其配置为在 Linux 上工作,而不是分叉。在 Windows 上,spawn 是默认设置,因此它在那里工作

然而,Python2 没有这个选项,我正在寻找另一个解决方案来运行它并收集要运行的场景列表

于 2014-08-28T15:11:42.337 回答