Let's say deleteInvocation=1, notDeletedInvocation=2
Does that mean I will have 3 records in the Post array before entering?
3 * postConverter.apply(Post, null) >> PostPayload
#Unroll
def "Verify PostCoreImpl.findById return Post when includeRemoved: [#includeRemoved]"() {
setup:
def PostId = UUID.randomUUID()
def Post = Mock(Post)
def PostPayload = Mock(PostPayload)
when:
def actual = underTest.findPostById(PostId, includeRemoved, false, false)
then:
deleteInvocation * mockPostDataManager.findByIdincludeRemoved(PostId) >> Post
notDeletedInvocation * mockPostDataManager.findById(PostId) >> Post
3 * postConverter.apply(Post, null) >> PostPayload
actual == PostPayload
where:
deleteInvocation | notDeletedInvocation | includeRemoved
1 | 0 | true
0 | 1 | false
}
First of all, I would advise against using variable names starting with capital letters, especially if these variables are identical with actual class names(!). For example, I would change
def PostId = UUID.randomUUID()
def Post = Mock(Post)
def PostPayload = Mock(PostPayload)
to
def postId = UUID.randomUUID()
def post = Mock(Post)
def postPayload = Mock(PostPayload)
and update all places where these variables are used.
As for your question, the notation integerNumber * methodCall(...) on a mock or spy object means that you want to verify that methodCall(...) was called exactly integerNumber times during your test (interaction checking).
Please consult the Spock manual chapter "Interactions" for further information.
The notation integerNumber * methodCall(...) >> stubResult means that you combine interactions with stubbing, i.e. specify two things at once with a mock or spy object.
Please consult the Spock manual chapter "Combining Mocking and Stubbing" for further information.
Related
I'm trying to check if commit-msg from git contains particular ticket number with project key of Jira using groovy in Jenkins pipeline
def string_array = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def string_msg = 'CO-10389, CO-10302 new commit'
To extract numbers I am using below logic.
findAll( /\d+/ )*.toInteger()
Not sure how to extract exact ticket number with project key.
Thanks in advance.
You could use Groovy's find operator - =~, combined with a findAll() method to extract all matching elements. For that, you could create a pattern that matches CO-\d+ OR DEOPSDESK-\d+ OR ..., and so on. You could keep project IDs in a list and then dynamically create a regex pattern.
Consider the following example:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, CO-10302 new commit'
// Generate a pattern "CO-\d+|DEVOPSDEKS-\d+|SEC-\d+|...
def pattern = projectKeys.collect { /${it}-\d+/ }.join("|")
// Uses =~ (find) operator and extracts matching elements
def jiraIds = (commitMessage =~ pattern).findAll()
assert jiraIds == ["CO-10389","CO-10302"]
// Another example
assert ("SEC-1,REL-2001 some text here" =~ pattern).findAll() == ["SEC-1","REL-2001"]
The regex can be assembled a bit simpler:
def projectKeys = ['CO', 'DEVOPSDESK', 'SEC', 'SRE', 'SRE00IN', 'SRE00EU', 'SRE00US', 'REL']
def commitMessage = 'CO-10389, REL-10302 new commit'
String regex = /(${projectKeys.join('|')})-\d+/
assert ['CO-10389', 'REL-10302'] == (commitMessage =~ regex).findAll()*.first()
You can have also another option with finer contol over matching:
def res = []
commitMessage.eachMatch( regex ){ res << it[ 0 ] }
assert ['CO-10389', 'REL-10302'] == res
I am trying to run following query through Rails query interface but unable to translate my logic. The query is
Select f.* from feeds f
Left join feed_items fi on fi.id = f.feedable_id
where
f.feedable_type in ('Homework', 'Datesheet')
and
(
(fi.assignable_type = 'Level' and assignable_id IN (1)) or
(fi.assignable_type = 'Student' and assignable_id IN (1)) or
(fi.assignable_type = 'Section' and assignable_id IN (1))
)
Scenario:
I receive following params hash in my action containing filters which will be added dynamically in my query
{"page"=>"1", "limit"=>"2", "type_filter"=>["Homework", "Datesheet"], "assignable_filter"=>{"Student"=>"[2]", "Section"=>"[1]", "Level"=>"[1]"}}
So far, what I have done is joining the tables and added where clause for type filter but not sure how to dynamically add assignable_filters. Here is my rails code, options are params in following code
def get_feeds(options)
base = Feed.includes(:feed_item)
base = add_type_filters base, options
base = add_assignable_filters base, options
format_response base, options
end
def add_type_filters(base, options)
type_filter = options[:type_filter]
if !type_filter.nil? and type_filter.length > 0
base = base.where('feedable_type IN (?)', options[:type_filter])
end
base
end
def add_assignable_filters(base, options)
assignable_filter = options[:assignable_filter]
if !assignable_filter.nil?
assignable_filter.each do |key, value|
# code for adding filters combined with or conditions
end
# wrap the or conditions and join them with an and in main where clause
end
base
end
P.S I am using rails 5
There was no straight forward way of building the query dynamically. I had to construct the where string to solve the problem. My current solution is
def get_feeds(options)
params_hash = {}
type_filters = add_type_filters options, params_hash
assignable_filters = add_assignable_filters options, params_hash
where = type_filters
where = where ? "#{where} and (#{assignable_filters})" : assignable_filters
base = Feed.eager_load(:feed_item).where(where, params_hash)
format_response base, options
end
def add_type_filters(options, params_hash)
type_filter = options[:type_filter]
type_filter_sql = nil
if !type_filter.nil? and type_filter.length > 0
type_filter_sql = 'feeds.feedable_type in (:type_filter)'
params_hash[:type_filter] = type_filter
end
type_filter_sql
end
def add_assignable_filters(options, params_hash)
assignable_filter_sql = []
assignable_filter = options[:assignable_filter]
if !assignable_filter.nil?
assignable_filter.each do |key, value|
assignable_filter_sql.push("(feed_items.assignable_type = '#{key}' and feed_items.assignable_id IN (:#{key}))")
params_hash[key.to_sym] = JSON.parse(value)
end
end
assignable_filter_sql.join(' or ')
end
I have an issue with the code below, it takes no argument, and i am suppose to create a method to return the answer. I don't know how to get the value passed.
And please what is the name of this concept, so i can read it up.
describe "reverser" do
it "reverses the string returned by the default block" do
result = reverser do
"hello"
end
result.should == "olleh"
end
end
def reverser(sent)
words = sent.split(" ")
i = 0
while i < words.length
words[i] = words[i].reverse
i += 1
end
words.join(" ")
end
def reverser
yield.reverse
end
Here is the code in question:
result = reverser do
"hello"
end
That is equivalent to:
result = reverser() do
"hello"
end
Breaking that down:
method call -+ +- 'do' marks the start of the block
| |
V V
result = reverser() do
"hello"
end
^
|
+--- end of the block
A block is like a method, and it's as if the block is passed as an invisible argument to the reverse() method. Inside reverse(), you can call the block using yield:
def reverser
return_value_of_block = yield
return_value_of_block.reverse
end
Writing yield, or yield(), is like writing unamed_block_method(). In other words, yield is the name ruby gives to the block-method.
And if the block is supposed to take arguments, then the block will look like this:
result = do_stuff do |x|
x * 2
end
And do_stuff() will look like this:
def do_stuff
return_value_of_block = yield(4) #call block with the argument 4
end
And please what is the name of this concept, so i can read it up.
Search for ruby blocks.
Your reverser takes a block which you call to get it return value:
def reverser(&block)
string = block.call
string.reverse
end
Note: You do not need the string variable. I just use it for readability reasons. You can also just write block.call.reverse.
I have a function that generates random output (string).
I need to call that function until I get 3 different outputs (strings).
What is the most elegant way to generate array with 3 unique strings by calling the function, with the limit how many times the function can be called if the output is not generated in specified number of attempts?
Here's what I currently have:
output = []
limit_calls = 5
limit_calls.times do |i|
str = generate_output_function
output.push str
break if output.uniq.size > 2
end
Can this be beautified / shortened to 1 line? I'm pretty sure in ruby.. :)
Thanks
Using a set makes it (a bit) easier:
require 'set'
output = Set.new
limit_calls = 5
call_count = 0
while output.size < 3 and call_count < limit_calls
output << generate_output_function
call_count += 1
end
output
or with an array
output = []
limit_calls = 5
while output.size < limit_calls and output.uniq.size < 3
output << generate_output_function
end
output.uniq
UPDATE with the call limit. Seems like the Array version wins! Thanks Iain!
Will also ponder a version using inject.
UPDATE 2 - with inject:
5.times.inject([]) { |a, el| a.uniq.size < 3 ? a << generate_output_function : a }
there is your oneliner. I am not sure I prefer it cause it is a bit hard to follow.....
Froderik's answer missed out the call_limit requirement. What about a function like...
def unique_string_array(call_limit)
output = []
calls = 0
until (output.size == 3 || calls == call_limit) do
(output << generate_output_function).uniq! && calls+=1
end
output
end
It isn't a one-liner but it is readable... with this implementation, you may end up with arrays less than size 3. The most important thing is that you have a test that asserts the behaviour you want! (in order to test this thoroughly you'll have to stub out the call to generate_output_function)
I trying to build a dynamic query similar to:
def domain = DomainName
def ids = 1
def domainClass = "$domain" as Class
domainClass.find("from ${domain} as m where m.job = ${ids} ").id
But it's not working.
If I'm trying this, all is fine:
def domain = DomainName
def ids = 1
DomainName.find("from ${domain} as m where m.job = ${ids} ").id
How can I use dynamic domain class name with find?
The simplest way is to use the getDomainClass method:
String domainClassName = 'com.foo.bar.Person'
def ids = 1
def domainClass = grailsApplication.getDomainClass(domainClassName).clazz
domainClass.find("from $domainClassName as m where m.job = ${ids} ").id
Note that if you're trying to get a single instance by id, use get:
long id = 1234
def person = domainClass.get(id)
and if you want to get multiple instances and you have a list of ids, you can use getAll
def ids = [1,2,3,4,5]
def people = domainClass.getAll(ids)
Also it's a REALLY bad idea to use GStrings with property values embedded - Google 'SQL Injection'
For example to find a person by username:
String username = 'foo'
def person = domainClass.find(
"from $domainClassName as m where m.username=:username",
[username: username])
You should be able to do this by explicitly using the GroovyClassLoader:
def domain = "DomainName"
def c = new GroovyClassLoader().loadClass(domain)
c.find('...').id
The best way to get a Domain class dynamically is through the GrailsApplication object. Example:
import org.codehaus.groovy.grails.commons.ApplicationHolder
def domainName = "full.package.DomainName"
def domainGrailsClass = ApplicationHolder.application.getArtefact("Domain", domainName)
def domainClass = domainGrailsClass.getClazz()
domainClass.find("from ${domainGrailsClass.name} as m where m.job = ${ids}").id
You can also use Class.forName() just as you would in Java. Use the 3 parameter version and pass in the current thread context class loader:
import grails.util.GrailsNameUtils
def domainName = "full.package.DomainName"
def domainClass = Class.forName(domainName, true, Thread.currentThread().getContextClassLoader())
domainClass.find("from ${GrailsNameUtils.getShortName(domainName)} as m where m.job = ${ids}").id
Classloaders are an ugly topic in Java and JVM frameworks. In Grails, you almost always want to use the thread context classloader. But even better is to use the GrailsApplication interface and avoid the issue altogether.
use GrailsClassUtils
GrailsClassUtils.getShortName(DomainName)
to get the name of the class, so this should work... if I understood the question
def domainClassName = GrailsClassUtils.getShortName(DomainName)
def ids = 1
DomainName.find("from ${domainClassName} as m where m.job = ${ids} ").id