1

我有一个相当基本的 puppet 模块,用于运行 tomcat 的 web 服务。我想在 Tomcat 的catalina.out文件上设置 logrotate,我想首先编写一个测试,确认 logrotate 包含在模块中并使用正确的设置进行设置。

这是 my 的精简版webservice.pp,例如:

class my_module::webservice (
  ...
){
  include ::tomcat_server

  ...

  logrotate::rule { 'tomcat':
    path          => '/var/log/tomcat/catalina.out',
    rotate        => 1,
    rotate_every  => 'day',
    copytruncate  => true,
    missingok     => true,
    compress      => true,
    delaycompress => true,
  }
}

我已经在我的.fixtures.yml喜欢中包含了 logrotate forge 模块:

fixtures:
  forge_modules:
    logrotate:
      repo: 'puppet-logrotate'
      ref:  '3.2.1'
    ...

但我只能编写一个测试来确认它logrotate包含在模块中,如下所示:

require 'spec_helper'

describe 'my_module::webservice' do
  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) { os_facts }

      it { is_expected.to compile }

      it { is_expected.to contain_class('logrotate') }
    end
  end
end

这不起作用(如果我从中删除 logrotate 块,init.pp测试仍然通过):

it { is_expected.to contain_class('logrotate::conf') }

也不要求with

it { is_expected.to contain_class('logrotate') \
  .with('path'          => '/var/log/tomcat/catalina.out',
        'rotate'        => 1,
        'rotate_every'  => 'day',
        'copytruncate'  => true,
        'missingok'     => true,
        'compress'      => true,
        'delaycompress' => true,
  )
}

也没有单独的/嵌套的describe块:

describe 'logrotate::rule' do
  let(:title) { 'tomcat' }
  let(:params) do
    {
        'path'          => '/var/log/tomcat/catalina.out',
        'rotate'        => 1,
        'rotate_every'  => 'day',
        'copytruncate'  => true,
        'missingok'     => true,
        'compress'      => true,
        'delaycompress' => true,
    }
  end
end

我在 rspec 文档中找不到任何提到除了测试定义的类之外的任何内容。甚至有可能做我想做的事吗?

这是我的目录布局:

puppet
  `- modules
        `- my_module
             |- data
             |- manifests
             |    |- init.pp
             |    `- webservice.pp
             |- spec
             |    |- classes
             |    |    `- webservice_spec.rb
             |    `- spec_helper.rb
             |- .fixtures.yml
             |- Gemfile
             |- hiera.yaml
             |- metadata.json
             `- Rakefile
4

1 回答 1

3

我有一个相当基本的 puppet 模块,用于运行 tomcat 的 web 服务。我想在 Tomcat 的 catalina.out 文件上设置 logrotate,我想首先编写一个测试,确认 logrotate 包含在模块中并使用正确的设置进行设置。

这听起来很合理。然而,这...

这是我的 init.pp 的精简版本,例如:

class my_module::webservice (
  ...
){

......充其量是糟糕的做法。如果它存在,那么init.ppmodule 的清单my_module应该只定义 class my_module。一个名为的类my_module::webservice应该在名为webservice.ppmodule的清单中定义my_module。Puppet 在线文档中记录了对模块布局的期望。尽管您可能能够摆脱这些规范的某些差异,但这样做只有缺点。

在这一点上,我观察到“内部阶级”不是惯用的 Puppet 术语,它暗示了对您正在使用的内容的误解。具体来说,这...

logrotate::rule { 'tomcat':

[...]

... 根本没有声明一个,而是声明了一个type的资源logrotate::rule,这显然是 puppet/logrotate 模块提供的定义类型。通常,声明资源并不意味着提供资源类型的模块(如果有)中的任何类。

此外,虽然完全有可能声明logrotate::rule资源确实会导致类logrotate也包含在目录中,但这将是 的实现细节logrotate::rule,因此,您的规范测试不应该对其进行测试。只有当my_module::webservice期望自己声明类logrotate时,它的测试才应该检查它。

你接着说:

这不起作用(如果我从 init.pp 中删除 logrotate 块,那么测试仍然通过):

it { is_expected.to contain_class('logrotate::conf') }

您还没有为我们提供足够的代码来确定当测试包含在测试中时为什么会通过,但是如果满足了这种期望,那就很奇怪了。logrotate::conf也是定义的(资源)类型,而不是类,因此期望永远不会成功。按照我上面介绍的主题,如果类my_module::webservice没有logrotate::conf直接声明任何资源,那么它的测试不应该检查一个。

也不要求:

it { is_expected.to contain_class('logrotate') \
  .with('path'          => '/var/log/tomcat/catalina.out',
        'rotate'        => 1,
        'rotate_every'  => 'day',
        'copytruncate'  => true,
        'missingok'     => true,
        'compress'      => true,
        'delaycompress' => true,
  )
}

当然这不会成功。它表达了对 class 声明的期望logrotate,但您实际声明的是 type 的资源logrotate::rule。即使logrotate::rule确实声明logrotate了,也不会期望它传递自己的参数列表。

也没有单独的/嵌套的描述块:

describe 'logrotate::rule' do

[...]

同样,这并不奇怪。这样的describe块告诉 RSpec 那logrotate::rule是被测试的类。它不仅不是被测试的类(当然是my_module::webservice),而且,同样,logrotate::rule它根本不是一个类。RSpec 当然也可以测试定义的类型,但这不是你想要的。

为了测试资源是否由被测类声明,可以使用表单contain_类型(title)的谓词,其中类型名称中的任何命名空间分隔符 ( ::) 都替换为双下划线。例如:

it do
  is_expected.to contain_logrotate__rule('tomcat')
end

允许但可选地包含一个或多个with子句来指定对指定资源的声明参数的期望。那么,按照您似乎一直在尝试做的事情,也许这会更充分地表达您正在寻找的东西:

require 'spec_helper'

describe 'my_module::webservice' do
  on_supported_os.each do |os, os_facts|
    context "on #{os}" do
      let(:facts) { os_facts }

      it do
        is_expected.to compile
        is_expected.to contain_logrotate__rule('tomcat')
          .with(
            path: '/var/log/tomcat/catalina.out',
            rotate: 1,
            rotate_every: 'day',
            copytruncate: true,
            missingok: true,
            compress: true,
            delaycompress: true
          )
      end
    end
  end
end

顺便说一句,请注意,当您想针对同一个示例测试多个谓词时,将它们组合在同一个it块中(如上所示)比将每个谓词放在自己的it块中要有效得多。例如,即使将两个it块合并为一个,您也可能会注意到测试运行时间的差异。

此外,我上面的示例演示的编码风格接近于避免来自 的警告所需的风格pdk validate,这给我们带来了另外一点:在尝试单元测试之前验证pdk validate完成时没有错误或警告总是有用的。您可能会发现它对 Puppet 和 Ruby 代码风格都过于挑剔,但它也会挑出一些导致神秘测试失败的问题。此外,它的运行速度比测试快得多,而且它可以检测 Puppet 和 Ruby 代码中的几乎所有语法错误。由于轻微的语法错误,您的测试需要很长时间才能失败,这令人沮丧。

于 2020-01-20T17:28:39.477 回答