Cannot create web documentation from on_flow_end callback - origen-sdk

I'm trying to setup origen to automatically generate web documentation after generating a flow with the origen p command, so I added the following callback:
def on_flow_end(options)
OrigenDocHelpers.generate_flow_docs layout: "#{Origen.root}/templates/web/layouts/_basic.html.erb", tab: :flows do |d|
d.page flow: "#{options[:test_module]}_flow".to_sym,
name: "#{options[:test_module].to_s.upcase} Flow",
target: "#{Origen.target.name}.rb"
end
end
This causes an error when building the flow page:
[INFO] 14.641[0.005] || Building flow page: /users/chorton/osdk/ppekit/web/content/flows/pcie_flow.md
COMPLETE CALL STACK
-------------------
Can't find: partials/_navbar.html
/home/chorton/.origen/gems/ruby/2.3.0/bundler/gems/origen-7bf48a874995/lib/origen/file_handler.rb:137:in `clean_path_to'
/home/chorton/.origen/gems/ruby/2.3.0/bundler/gems/origen-7bf48a874995/lib/origen/file_handler.rb:226:in `rescue in clean_path_to_sub_template'
/home/chorton/.origen/gems/ruby/2.3.0/bundler/gems/origen-7bf48a874995/lib/origen/file_handler.rb:213:in `clean_path_to_sub_template'
/home/chorton/.origen/gems/ruby/2.3.0/bundler/gems/origen-7bf48a874995/lib/origen/generator/renderer.rb:8:in `render'
(erb):4:in `_get_binding'
There is no error if I separately call origen p (without the added callback) and then run:
origen web compile --remote --api
Is it possible to combine the two into one command with a callback like I'm trying to do or is it necessary for origen web compile to be called after origen p?
Thanks.

This does seem like a bug, please open a ticket for it here if you cannot get it resolved - https://github.com/Origen-SDK/origen/issues
I would say that the convention normally used to do this is to hook into the after_web_site_compile callback in your config/application.rb.
Here is an example:
# config/application.rb
def after_web_site_compile(options)
# Build the test flow docs
Origen.environment.temporary = 'v93k.rb'
# Generate the program for the target(s) you want to document
%w(device_a device_b).each do |target|
Origen.target.temporary = "#{target}.rb"
Origen.app.runner.launch action: :program,
files: 'program/full.list' # Or whatever file arg you pass to 'origen p'
OrigenDocHelpers.generate_flow_docs layout: "#{Origen.root}/templates/web/layouts/_basic.html.erb", tab: :flows do |d|
d.page flow: "#{options[:test_module]}_flow".to_sym,
name: "#{options[:test_module].to_s.upcase} Flow",
target: "#{target}.rb"
end
end
end

Related

Codeception doesn't override parameter in Gitlab

I have this issue
*********** codeception.yml ***************
paths:
tests: tests
output: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
actor_suffix: Tester
#amount customer per product
amountPerProduct: 1
wishCountry: 1
wishProduct: 0
I am using the param like this:
$countryIndex = Configuration::config()['wishCountry'];
but on the console I calling the test like this:
codecept run tests/acceptance/ChangeCest.php --env chrome --xml --html -o "wishProduct:55"
I get this error:
enter image description here
QUESTION: how can I override this config in Gitlab?
Thank you
Not entirely sure if this solves your problem but for Codeception v5 (also my current local version v4.2.1) the option is exploded with : , i.e. with an appended space. I notice in your screenshot the exception does show the key/value without the space in between, but you didn't specify which version of Codeception you're using.
From Config.php:
foreach ($configOptions as $option) {
$keys = explode(': ', $option);
// ^ notice the space here
if (count($keys) < 2) {
throw new \InvalidArgumentException('--override should have config passed as "key: value"');
}
https://github.com/Codeception/Codeception/blob/5.0/src/Codeception/Command/Shared/ConfigTrait.php
i find the answer to my problem.
I store the parameters in a new file params.yml
params.yml
parameters:
WISH_PRODUCT: 55
codeception.yml
params:
- params.yml
acceptance.suite.yml
config:
custom_params:
wishProduct: %WISH_PRODUCT%
AcceptanceTester.php
so in AcceptanceTester I can read the values like this
$custom_params = Configuration::suiteSettings('acceptance', Configuration::config())['modules']['custom_params'];

How to pass a stage variable to lambda function in api gateway using AWS CDK?

I have an API Gateway that triggers a lambda function specified by a stage variable stageVariables.lbfunc.
How can I create this kind of integration request with AWS CDK?
It looks like that I should create a special handler for LambdaRestApi.
But I can't find any example code for doing this.
The following is my current code. I wish that LambdaIntegration's handler can be determined by a stage variable.
# dev_lambda_function should be replaced by something else
dev_lambda_function = lambda_.Function(self, "MyServiceHandler",
runtime=lambda_.Runtime.PYTHON_3_7,
code=lambda_.Code.asset("resources"),
handler="lambda_function.lambda_handler",
description="My dev lambda function"
)
stage_options = apigateway.StageOptions(stage_name="dev",
description="dev environment",
variables=dict(lbfunc="my-func-dev")
)
# What should I pass to the handler variable so that LambdaRestApi triggers the lambda function specified by the stage variable "stageVariables.lbfunc"?
api = apigateway.LambdaRestApi(self, "my-api",
rest_api_name="My Service",
description="My Service API Gateway",
handler=dev_lambda_function,
deploy_options=stage_options)
Just solved this recently, I just record down how I solved it here (before I forget)
The idea here is, when your API method get hit, it will make a POST request your lambda. So you make a "URL" of your lambda, so your API method can hit that. (Ok, I finally found it, you can read it here, for item No.6 in this link, look the URI there)
Create a Construct called ApiIntegration:
class ApiIntegration(core.Construct):
#property
def integration(self):
return self._integration
def __init__(self, scope: core.Construct, id: str, function: _lambda, ** kwargs):
super().__init__(scope, id, **kwargs)
# Here you construct a "URL" for your lambda
api_uri = (
f"arn:aws:apigateway:"
f"{core.Aws.REGION}"
f":lambda:path/2015-03-31/functions/"
f"{function.function_arn}"
f":"
f"${{stageVariables.lambdaAlias}}" # this will appear in the picture u provide
f"/invocations"
)
# Then here make a integration
self._integration = apigateway.Integration(
type=apigateway.IntegrationType.AWS_PROXY,
integration_http_method="POST",
uri=api_uri
)
In your MyStack(core.Stack) class you can use it like this:
# Here u define lambda, I not repeat again
my_lambda = ur lambda you define
# define stage option
dev_stage_options = apigateway.StageOptions(
stage_name="dev",
variables={
"lambdaAlias": "dev" # define ur variable here
})
# create an API, put in the stage options
api = apigateway.LambdaRestApi(
self, "MyLittleNiceApi",
handler=my_lambda,
deploy_options=dev_stage_options
)
# Now use the ApiIntegration you create
my_integration = ApiIntegration(
self, "MyApiIntegration", function=my_lambda)
# make a method call haha
my_haha_method = api.root.add_resource("haha")
# put in the integration that define inside the Construct
my_haha_post_method = my_method.add_method('POST',
integration=my_integration.integration,
#...then whatever here)
By now you check your console, your method will have Lambda function with stageVariable.
Now you should create the lambda alias, the idea is like this:
You have 1 lambda
Make 2 alias for the lambda, dev and prod
API stageVariable dev -> hit -> lambda dev alias
API stageVariable prod -> hit -> lambda prod alias
Each lambda alias will hit different version of your lambda, for example:
dev alias hit $Latest
prod alias hit version:12
I have talk about this in dev.to here
Now you have lambda:dev and lambda:prod 2 alias.
In order to let your method to hit different alias lambda:dev and lambda:prod, you need (The main idea):
Lambda dev/prod alias give permission to method to hit on.
Create version, alias and permission stuff is whole different story, so didnt mention here.

Can callbacks be used to configure remotes?

I was reading the Origen documentation on remotes and had a question. When do the remote files get retrieved relative to the Origen callbacks? The reason i ask is that the files we want to retrieve would be used to construct our DUT model and there are some order dependencies.
I have tried all of the existing callbacks, in an attempt to configure the remotes, with no success.
def pre_initialize
Origen.app.config.remotes = [
{
dir: 'product',
vault: 'ssh://git#stash.com/myproduct/origen.git',
version: '0.1.0'
}
]
end
If I add the remotes config to the application file it works:
config.remotes = [
{
dir: 'product',
vault: 'ssh://git#stash.com/myproduct/origen.git',
version: '0.1.0'
}
]
The problem with using the config/application.rb file is that we can't keep product specific information anywhere in our application space. We use symbolic links to map to source files that are stored in test program stash repositories. I think we may need a new callback, please advise.
thx
** EDIT **
So I defined the remotes in another file and call the method to actually do it in the boot.rb file. Then I placed the remote manager require method in the on_create callback but got no remotes fetched.
284: def on_create
285: binding.pry
=> 286: Origen.remote_manager.require!
287: end
[1] pry(#<PPEKit::Product>)> Origen.config.remotes
=> [{:dir=>"remote_checkout", :rc_url=>"ssh://git#stash.us.com:7999/osdk/us-calendar.git", :version=>"v0.1.0"}]
[2] pry(#<PPEKit::Product>)>
origen(main):001:0>
It seems like the Origen.remote_manager.require! is not working. So I checked the remotes manager file and don't see how the require! method could ever work with a callback because it seems to be checking the remotes are dirty, which can never happen for a remote definition that was set after the application.rb file was loaded. So I created a resolve_remotes! method that seems to work:
def resolve_remotes!
resolve_remotes
remotes.each do |_name, remote|
dir = workspace_of(remote)
rc_url = remote[:rc_url] || remote[:vault]
tag = Origen::VersionString.new(remote[:version])
version_file = dir.to_s + '/.current_version'
begin
if File.exist?("#{dir}/.initial_populate_successful")
FileUtils.rm_f(version_file) if File.exist?(version_file)
rc = RevisionControl.new remote: rc_url, local: dir
rc.checkout version: prefix_tag(tag), force: true
File.open(version_file, 'w') do |f|
f.write tag
end
else
rc = RevisionControl.new remote: rc_url, local: dir
rc.checkout version: prefix_tag(tag), force: true
FileUtils.touch "#{dir}/.initial_populate_successful"
File.open(version_file, 'w') do |f|
f.write tag
end
end
rescue Origen::GitError, Origen::DesignSyncError => e
# If Git failed in the remote, its usually easy to see what the problem is, but now *where* it is.
# This will prepend the failing remote along with the error from the revision control system,
# then rethrow the error
e.message.prepend "When updating remotes for #{remote[:importer].name}: "
raise e
end
end
end
The resolve_remotes! method just forces all known remotes to be fetched. Would a PR be accepted for this solution?
thx
Remotes are currently required at application load time, which means it occurs before any of the application call back points.
The content of config.remotes can still be made dynamic by assigning it in a block:
config.remotes do
r = [{
dir: 'product',
vault: 'ssh://git#stash.com/myproduct/origen.git',
version: '0.1.0'
}]
if some_condition
r << { dir: ... }
end
r
end
The config.remotes attribute will be evaluated before the target is loaded however, so you won't be able to reference dut for example, though maybe that is good enough.
Alternatively, you could implement a post target require of the remotes within your application pretty easily.
Make the remotes return en empty array if the dut is not available yet, that will make it work ok when it is called by Origen during application load:
config.remotes do
if dut
# As above example
else
[]
end
end
Then within the callback handler of your choice:
Origen.remote_manager.require!
That should cause it to re-evaluate config.remotes and fetch any remotes that are missing.

post test execution callbacks available?

I am looking to apply a callback post test execution that will check for an alarm flag. I don't see any listed here so I then checked the test interface and only see what looks like a flow level callback:
# This will be called at the end of every flow or sub-flow (at the end of every
# Flow.create block).
# Any options passed to Flow.create will be passed in here.
# The options will contain top_level: true, whenever this is called at the end of a
# top-level flow file.
def shutdown(options = {})
end
We need the ability to check the alarm flags after every test but still apply a common group ID to a list of tests like this:
group "func tests", id: :func do
[:minvdd, :maxvdd].each do |cond|
func :bin1_1200, ip: :cpu, testmode: :speed, cond: cond
end
end
Here is an example of the V93K alarm flow flag:
thx!
It is common when writing interfaces to funnel all test generation methods through a common single method to add them to the flow:
def func(name, options = {})
t = test_suites.add(name)
t.test_method = test_methods.origen.functional_test(options)
add_to_flow(t, options)
end
def para(name, options = {})
t = test_suites.add(name)
t.test_method = test_methods.origen.parametric_test(options)
add_to_flow(t, options)
end
def add_to_flow(test_obj, options = {})
# Here you can do anything you want before adding each test to the flow
flow.test(test_obj, options)
# Here you can do anything you want after adding each test to the flow
end
So while there is no per-test callback, you can generally achieve whatever you wanted to do with one via the above interface architecture.
EDIT:
With reference to the alarm flag flow structure you want to create, you would code it like this:
func :some_func_test, id: :sft1
if_failed :sft1 do
bin 10, if_flag: "Alarm"
bin 11, unless_flag: "Alarm"
end
Or, if you prefer, this is equivalent:
func :some_func_test, id: :sft1
bin 10, if_flag: "Alarm", if_failed: :sft1
bin 11, unless_flag: "Alarm", if_failed: :sft1
At the time of writing, that will generate something logically correct but with a sub-optimal branch structure.
In the next release that will be fixed, see the test case that has been added here and the output it generates here.
You can call all of the flow control methods from the interface the same way you can from within the flow, so you can inject such conditions in the add_to_flow method if you want.
Note also that in the test case both if_flag and if_enable are used. if_enable should generally be used if the flag is something that would be set at the start of the flow (e.g. by the operator) and would not change. if_flag should be used if it is a flag that is subject to modification by the flow at runtime.

Using Pickle with spork?

Pickle doesn't seem to be loading for me when I'm using spork...
If I run my cucumber normally, the step works as expected:
➜ bundle exec cucumber
And a product exists with name: "Windex", category: "Household Cleaners", description: "nasty bluish stuff" # features/step_definitions/pickle_steps.rb:4
But if I run it through spork, I get an undefined step:
You can implement step definitions for undefined steps with these snippets:
Given /^a product exists with name: "([^"]*)", category: "([^"]*)", description: "([^"]*)"$/ do |arg1, arg2, arg3|
pending # express the regexp above with the code you wish you had
end
What gives?
So it turns out there is an extra config line necessary for features/support/env.rb when using spork in order to have Pickle be able to pickup on AR models, a la this gist:
In features/support/env.rb
Spork.prefork do
ENV["RAILS_ENV"] ||= "test"
require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
# So that Pickle's AR adapter properly picks up the application's models.
Dir["#{Rails.root}/app/models/*.rb"].each { |f| load f }
# ...
end
Adding in this line fixes my problem. This is more of a spork issue than guard, per se. I'll update my question...

Resources