2

我们的开发应用程序有大约 12 个本土插件和许多 Origen gem,需要从开发到生产级质量。我从这里开始看到许多杂项主题,但我在应用程序/插件版本控制、Origen 模式(调试和生产)以及参考文件和示例等项目上看不到太多。我知道有运行 rspec 的“origen specs”命令,但是“origen test”和其他相关项目呢?

谢谢

4

1 回答 1

2

是的,关于这个主题的文档有点薄,这里有一些信息可以解决这个问题:

运行时模式

是的,Origen 确实有调试和生产模式的概念 - http://origen-sdk.org/origen/guides/runtime/mode/

在生产模式下运行确实为您提供了一些基本保护,防止本地编辑进入生产构建,但实际上我认为今天有许多生产项目一直只使用调试模式。

我认为生产模式的主要好处是您可以使用它来实现您关心的特定领域的检查。例如,在我的一个应用程序中,我有一个before_generate回调处理程序,用于检查我们正在使用的产品固件是否是我们为生产而构建时发布的最新版本。

另一种有用的技术是将模式嵌入到应用程序生成的程序、模式或测试名称等内容中。如果有人对他们想要发布到生产环境的东西使用了调试版本,这就很清楚了。

版本控制

公司内部插件应以与 Origen 和开源插件相同的方式进行版本标记和发布。

通常每个人都通过运行origen rc tag命令来执行此操作,该命令将标记插件,维护发布历史,并构建 gem 并将其发布到您的 gem 服务器。

插件通常应注意不要在其.gemspec文件中锁定其依赖项的特定版本,而应指定最低版本。这样的事情很好,这意味着任何大于 1.2.3: 的依赖版本 1: '~>1', '>1.2.3'。有关如何指定 gem 版本的更多信息,请参见此处:http: //guides.rubygems.org/patterns/#declaring-dependencies

另一方面,顶级应用程序通常希望锁定到它们内部的特定版本的 gem,Gemfile以便它们的构建是可重现的。从理论上讲,您可以通过签入文件免费获得它,Gemfile.lock这意味着当捆绑器在新工作区中构建 gem 包时,它将使用该文件中指定的确切版本,即使其中的规则Gemfile可能允许一系列可能的版本。在实践中,许多工程师更喜欢通过在他们的Gemfile.

单元测试

单元测试几乎总是通过 rspec 工具完成,并且按照惯例通过origen specs命令启动。

单元测试很好,因为它们可以针对非常特定的功能,因此当它们失败时它们相对容易调试。

这些测试通常对于进行测试驱动开发非常有用,尤其是在创建新 API 时。该技术是使用编写测试的行为来定义您希望拥有的 API,然后进行所需的更改以使测试通过。

这些测试的缺点是它们需要时间来编写,并且在时间压力下通常会被放弃。编写它们也是一门艺术,有时经验不足的工程师可能很难知道如何编写针对特定功能的测试。

出于这个原因,单元测试更倾向于在插件中使用,特别是那些为父应用程序提供 API 的插件。顶级应用程序,尤其是那些与生成模式或测试程序有关的应用程序,往往依赖于基于差异的测试......

基于差异的测试

基于差异或验收测试,意味着有人祝福特定输出(即模式或测试程序文件)为“好”,然后可以创建测试,简单地说只要当前输出与一些先前已知的良好输出匹配,那么测试应该通过。

如果遇到差异,则测试将失败,工程师必须审查更改并确定是否不需要并突出显示真正的问题,或者更改是否可以接受/预期,在这种情况下,新输出应成为新输出已知良好的参考。

这种测试风格的优点是它不需要任何时间来编写测试,但它可以提供极高的测试覆盖率。缺点是有时很难找到不需要的差异的来源,因为测试覆盖了很大的表面积。另一个问题可能是,如果您进行全局影响所有输出的更改,不需要的差异可能会在噪音中丢失。因此,最好单独进行此类更改。

许多插件和 Origen 本身通过一个名为的命令实现这种测试风格,origen examples并将已知的良好输出检入approved目录中。

一些应用程序还实现了一个名为的命令origen test,它只是一个包装器,它组合origen specsorigen examples一个命令,这对于创建组合的测试覆盖率分析很有用(更多内容见下文)。

您应该参考一些开源存储库以获取有关如何创建这些命令的示例,但是所有新的 Origen 应用程序 shell 都应该附带在config/commands.rb.

当其占用空间相对较小时,签入已批准的输出是可以的,但是对于可能生成数千个模式或文件和/或支持许多不同目标的大型生产应用程序,那么签入所有内容就不那么实际了。

同样在这种情况下,有时说“与应用程序的版本 X 相比,输出中发生了什么变化?”而不是总是与最新的已知良好版本进行比较会变得更有用。

您可以通过检查应用程序的特定版本、生成输出然后使用origen save all命令在本地保存批准的输出来手动运行此类测试。然后检查您的应用程序的最新版本,再次运行相同的生成命令并查看是否有任何更改。

一段时间后,该工作流程可能会变得乏味,因此 Origen 通过回归管理器为其提供帮助:http: //origen-sdk.org/origen/api/Origen/RegressionManager.html

应用程序通常将其集成为一个名为origen regression.

下面包含了我的一个应用程序的完整实现和origen regression命令,以举例说明如何创建它。在这种情况下,我们使用 Origen 的 LSF API 来并行化命令,但如果您不使用它,只需替换Origen.lsf.submit_origen_job cmdsystem cmd在本地运行您的生成命令。

回归管理器将负责在应用程序的当前版本和以前版本中复制相同的命令,并为您提供差异结果。

请注意,build_reference: false如果您想针对您上次运行的应用程序的相同先前版本重新运行回归,您也可以提供。

测试覆盖率

-c使用或开关运行任何 Origen 命令--coverage将启用测试覆盖率报告的生成,您可以查看该报告以了解您的测试套件的运行情况。

这是覆盖率报告的示例 - http://origen-sdk.org/jtag/coverage/#_AllFiles


#commands/regression.rb
require 'optparse'

options = {}

default_targets = %w(product_a.rb product_b.rb)

short_targets = %w(product_a.rb)

opt_parser = OptionParser.new do |opts|
  opts.banner = 'Usage: origen regression [options]'
  opts.on('-t', '--target NAME1,NAME2,NAME3', Array, 'Override the default target, NAME can be a full path or a fragment of a target file name') { |t| options[:target] = t }
  opts.on('-e', '--environment ENV', String, 'Override the default environment (tester).') { |e| options[:environment] = e }
  opts.separator "        (default targets: #{default_targets})"
  opts.on('-s', '--short', 'Run a short regression (a single target)') { options[:short] = true }
  opts.separator "        (default short target: #{short_targets})"
  opts.on('-f', '--full', 'Run a full regression (all production targets)') { options[:full] = true }
  opts.on('-a', '--all', 'An alias for --full') { options[:full] = true }
  opts.on('-c', '--ci', 'Build for bamboo CI') { options[:ci] = true }  # avoids problematic targets for continuous integration
  opts.on('-n', '--no_reference', 'Skip the reference build (careful!). Use when re-running the same regression back-back.') { options[:build_reference] = false }
  opts.on('--email', 'Send yourself an email with the results when complete') { options[:send_email] = true }
  opts.on('--email_all', 'Send the results email to all developers') { options[:email_all_developers] = true; options[:send_email] = true }

  # Regression types-- saying no is easier to define the logic
  opts.on('--no-patterns', 'Skip the vector-based patterns in the regression test') { options[:no_patterns] = true }
  opts.on('--no-programs', 'Skip the programs in the regression test') { options[:no_programs] = true }

  # Regression type only-- have to omit all other regression types
  opts.on('--programs-only', 'Only do programs in the regression test') do
    options[:no_patterns] = true
  end
  opts.separator '        (NOTE: must run program-based regression first to get pattern list prior to pattern regressions)'
  opts.on('--patterns-only', 'Only do vector-based patterns in the regression test') do
    options[:no_programs] = true
  end

  opts.on('-v', '--version type', String, 'Version for the reference workspace, latest, last, tag(ex: v1.0.0) or commit') { |v| options[:version] = v }
  opts.on('--service_account', 'This option is set true only when running regressions through the Bamboo CI, a normal user should never have to use it') { options[:service_account] = true }
  opts.on('--reference_workspace location', String, 'Reference workspace location') { |ref| options[:reference_workspace] = ref }
  opts.separator ''
  opts.on('-h', '--help', 'Show this message') { puts opts; exit }
end
opt_parser.parse! ARGV

if options[:version]
  v = options[:version]
end

if options[:reference_workspace]
  ref = options[:reference_workspace]
end

if options[:target]
  t = options[:target]
  t[0].sub!(/target\//, '') if t.length == 1  # remove path if there-- causes probs below
elsif options[:short]
  t = short_targets
elsif options[:full]
  t = Origen.target.production_targets.flatten
else
  t = default_targets
end

if options[:environment]
  e = options[:environment]
  e.sub!(/environment\//, '') # remove path if there-- causes probs below
else
  e = 'v93k.rb'   # default environment
end

options[:target] = t
options[:environment] = e

def highlight(msg)
  Origen.log.info '######################################################'
  Origen.log.info msg
  Origen.log.info '######################################################'
end

# Required to put the reference workspace in debug mode since the regression.rb file is modified,
# in future Origen should take care of this
Origen.environment.temporary = "#{options[:environment]}"

Origen.regression_manager.run(options) do |options|
  unless options[:no_programs]
    highlight 'Generating test programs...'

    Origen.target.loop(options) do |options|
      cmd = "program program/full.list -t #{options[:target]} --list #{options[:target]}.list -o #{Origen.root}/output/#{Origen.target.name} --environment #{options[:environment]} --mode debug --regression"
      Origen.lsf.submit_origen_job cmd
    end

    highlight 'Waiting for test programs to complete...'

    Origen.lsf.wait_for_completion
  end

  unless options[:no_patterns]
    highlight 'Generating test patterns...'
    Origen.target.loop(options) do |options|
      # Generate the patterns required for the test program
      Origen.file_handler.expand_list("#{options[:target]}.list").each do |pattern|
        Origen.lsf.submit_origen_job "generate #{pattern} -t #{options[:target]} -o #{Origen.root}/output/#{Origen.target.name} --environment #{options[:environment]} --regression"
      end
    end
  end
end
于 2018-02-12T11:55:57.833 回答