GORM (varchar .save(), non DATE): ORA-01861: literal does not match format string - grails-orm

Hello I'm receiving a very strange error: ORA-01861: literal does not match format string. All my internet searching has related to DATE issues. Mine is just to save a simple string. If you see the issue please let me know how to fix it.
Column of issue
TREND: VARCHAR2(31, CHAR), no constraints
Mapped in GORM by:
String trend
...
static constraints = {
trend(nullable: true, blank: true)
... } ...
static mapping = {
trend column: "TREND", sqlType: "varchar(31)"
...}
Issue method:
def fix_trend(){
// There should ever only be three values found in the trend column
// of the Reports table: "TRENDING UP", "TRENDING STEADY", "TRENDING DOWN"
println "Running groovy database procedure : fix_trend"
StatusReport.list().each{
String trend = it.trend
if (trend != 'TRENDING UP' && trend != 'TRENDING STEADY' && trend != 'TRENDING DOWN'){
trend = trend?.toUpperCase()
if (trend == null){
trend = 'TRENDING STEADY'
}
else if (trend.contains('UP')){
trend = 'TRENDING UP';
}
else if (trend.contains('DOWN')){
trend = 'TRENDING DOWN';
}
else{
trend = 'TRENDING STEADY';
}
it.trend = trend;
it.save();
}
}
println "fix_trend completed"
}
The purpose of the method is to ensure all the values are either TRENDING UP, TRENDING DOWN, or TRENDING STEADY.
Stacktrace:
Running groovy database procedure : fix_trend
fix_trend completed
Error |
2015-01-05 10:53:02,392 [http-bio-8080-exec-4] ERROR spi.SqlExceptionHelper - ORA-01861: literal does not match format string
Error |
2015-01-05 10:53:02,481 [http-bio-8080-exec-4] ERROR errors.GrailsExceptionResolver - SQLDataException occurred when processing request: [GET] /investigator/statusReports/selection
ORA-01861: literal does not match format string
. Stacktrace follows:
Message: ORA-01861: literal does not match format string
Line | Method
->> 439 | processError in oracle.jdbc.driver.T4CTTIoer
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 395 | processError in ''
| 802 | processError . . . . in oracle.jdbc.driver.T4C8Oall
| 436 | receive in oracle.jdbc.driver.T4CTTIfun
| 186 | doRPC . . . . . . . in ''
| 521 | doOALL in oracle.jdbc.driver.T4C8Oall
| 205 | doOall8 . . . . . . in oracle.jdbc.driver.T4CPreparedStatement
| 1008 | executeForRows in ''
| 1307 | doExecuteWithTimeout in oracle.jdbc.driver.OracleStatement
| 3449 | executeInternal in oracle.jdbc.driver.OraclePreparedStatement
| 3530 | executeUpdate . . . in ''
| 1350 | executeUpdate in oracle.jdbc.driver.OraclePreparedStatementWrapper
| 16 | selection . . . . . in investigator.StatusReportsController
| 198 | doFilter in grails.plugin.cache.web.filter.PageFragmentCachingFilter
| 63 | doFilter . . . . . . in grails.plugin.cache.web.filter.AbstractFilter
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread

I solved my own issue.
There was a Date field in the table that was misrepresented as a String in the Domain class. Even though I was trying to update a VARCHAR2 field the domain_class.save() method updates every attribute of that domain_class-- thus the error was not associated with the TREND field but the misrepresented DATE field.
I figured this out by adding to DataSource.groovy
logSql = true
formatSql = true
and Config.groovy
log4j.main = {
trace 'org.hibernate.type'
debug 'org.hibernate.SQL'
...
This showed that the update statement generated by .save() tries to update EVERY attribute.
Hope this helps someone in the future.

Related

Where can i find the annotations for the api.order.search controller?

I need to write a new api endoint, very similar to the api/search/order endpoint using a custom implementation. Basically i want to add a new response format for another system.
This will also be a new route like api/custom/search/order.
My approach is that i want to write a new controller by extending the existing controller, defined as follows:
+--------------+---------------------------------------------------------------------------------------+
| Property | Value |
+--------------+---------------------------------------------------------------------------------------+
| Route Name | api.order.search |
| Path | /api/search/order{path} |
| Path Regex | {^/api/search/order(?P<path>(?:\/[0-9a-f]{32}\/(?:extensions\/)?[a-zA-Z-]+)*\/?)$}sDu |
| Host | ANY |
| Host Regex | |
| Scheme | ANY |
| Method | POST |
| Requirements | path: (\/[0-9a-f]{32}\/(extensions\/)?[a-zA-Z-]+)*\/? |
| | version: \d+ |
| Class | Symfony\Component\Routing\Route |
| Defaults | _controller: Shopware\Core\Framework\Api\Controller\ApiController::search() |
| | _routeScope: array (0 => 'api',) |
| | entityName: order |
| Options | compiler_class: Symfony\Component\Routing\RouteCompiler |
| | utf8: true |
+--------------+---------------------------------------------------------------------------------------+
From my current setup i was able to write a new controller but the controller can not be found in the routes as there is no annotation in the original one. I could add a custom annotation but i was looking at the original definition and actually there is no annotation.
public function search(Request $request, Context $context, ResponseFactoryInterface $responseFactory, string $entityName, string $path): Response
{
[$criteria, $repository] = $this->resolveSearch($request, $context, $entityName, $path);
$result = $context->scope(Context::CRUD_API_SCOPE, function (Context $context) use ($repository, $criteria): EntitySearchResult {
return $repository->search($criteria, $context);
});
$definition = $this->getDefinitionOfPath($entityName, $path, $context);
return $responseFactory->createListingResponse($criteria, $result, $definition, $request, $context);
}
My question is: Is there something like a dynamic annotation which will automatically be created? I can not find any information about how the path for /api/search/order{path} is defined.
/**
* #Route(defaults={"_routeScope"={"api"}})
*/
class OrderActionController extends ApiController
{
public function search(Request $request, Context $context, ResponseFactoryInterface $responseFactory, string $entityName, string $path): Response
{
}
}
I did figure it out. The annotations for the api.search.order are defined in the class Shopware\Core\System\CustomEntity\Api\CustomEntityApiController.
Shopware uses a dynamic annotation which will be used to create the routes. I was looking for a specific annotation and therefore was not able to find it.
#Route(
"/api/search/custom-entity-{entityName}{path}",
name="api.custom_entity_entity.search",
requirements={"path"="(\/[0-9a-f]{32}\/(extensions\/)?[a-zA-Z-]+)*\/?$"},
methods={"POST"}
)

istanbul generates empty report

I wanted to launch istanbul in my project, however no matter what I do reports shows only zeros. like below :
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 0 | 0 | 0 | 0 |
----------|---------|----------|---------|---------|-------------------
Even though it shows above the coverage report list of the test that passed. For simplicity I created super simple project for replication where I have only one function in indentity.js file :
export const identity = (x) => x;
and one simple test licated in test.js file
import { identity } from "./identity.js";
import assert from "assert";
describe("identity", function () {
it("should return passed argument", () => {
assert.equal(identity(1), 1);
assert.equal(identity("string"), "string");
assert.deepEqual(identity({ a: 1 }), { a: 1 });
});
});
and after I run nyc mocha I expect to see 100% coverage but what I have is the same table with zeros.
Is there some settings I missed to see proper coverage report ?
Thx in advance.

Using karate-config parameters in a feature file

The karate header examples do not show how to access config values other than baseUrl. When I switch environments (passing in -Dkarate.env=qual as part of the run command) then baseUrl is set correctly.
The problem is, I want to use other config values as shown here but when I run the test, it fails to access config.ApiKey correctly. Instead I get this error
html report:
file:/C:/bitbucket/karate-checkdigit-api/target/surefire-reports/TEST-features.checkdigitapi.VA.html
Tests run: 250, Failures: 0, Errors: 50, Skipped: 175, Time elapsed: 4.112 sec <<< FAILURE!
* def secretKey = config.apiKey(| XYZ | 2110974841 | 204 | Valid |) Time elapsed: 0.005 sec <<< ERROR!
java.lang.RuntimeException: no variable found with name: config
at com.intuit.karate.Script.getValuebyName(Script.java:323)
at com.intuit.karate.Script.evalJsonPathOnVarByName(Script.java:378)
at com.intuit.karate.Script.eval(Script.java:309)
at com.intuit.karate.Script.eval(Script.java:194)
at com.intuit.karate.Script.assign(Script.java:656)
at com.intuit.karate.Script.assign(Script.java:587)
at com.intuit.karate.StepDefs.def(StepDefs.java:265)
at ✽.* def secretKey = config.apiKey(features/checkdigitapi/XYZ.feature:6)
My .feature file and karate-config.js are below.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = config.apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: secretKey, Accept: 'application/json' }
Given path 'headers'
And param url = baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
| algo | custcode | val | comment |
| XYZ | 2110974841 | 204 | Valid |
| XYZ | 7790011614 | 204 | Valid |
| XYZ | 5580015174 | 204 | Valid |
| XYZ | 2110974840 | 400 | expected check digit 1 |
| XYZ | 211097484 | 400 | not 10 digits |
| XYZ | 211097484x | 400 | not numeric |
karate-config.js
function() {
//set up runtime variables based on environment
//get system property 'karate.env'
var env = karate.env;
if (!env) { env = 'dev'; } // default when karate.env not set
// base config
var config = {
env: env,
baseUrl: 'https://localapi.abc123.example.com/api/v1/validate/customerid',
apiKey: ''
}
//switch environment
if (env == 'dev') {
config.baseUrl = 'https://devapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-1ba403ca8938176f3a62de6d30cfb8e';
}
else if (env == 'qual') { //Pre-production environment settings
config.baseUrl = 'https://qualapi.abc123.example.com/api/v1/validate/customerid';
config.apiKey = 'fake-d5de2eb8c0920537f5488f6535c139f2';
}
karate.log('karate.env =', karate.env);
karate.log('config.baseUrl =', config.baseUrl);
karate.log('config.apiKey =', config.apiKey);
return config;
}
(similar issue here, using a separate headers.js: https://github.com/intuit/karate/issues/94)
Keep in mind that all the keys within the JSON object returned by karate-config.js will be injected as variables, and nothing else. So you will not be able to refer to config, but you will certainly be able to refer to apiKey.
I think if you make this simple change, things will start working:
* def secretKey = apiKey
Also, I think you have a problem in the first line of the scenario, it should be:
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
FYI my final, correctly working XYZ.feature file looks like this now.
The line Given path 'headers' caused header info to creep into the url so it's removed.
XYZ.feature
#regression
Feature: Checkdigit Algorithm API
Background:
* url baseUrl
* def secretKey = apiKey
* configure ssl = true
Scenario Outline: Testing XYZ algorithm
* configure headers = { KeyId: '#(secretKey)', Accept: 'application/json' }
Given url baseUrl
And params { customerId: '<custcode>', algoId: '<algo>' }
When method get
Then status <val>
Examples:
[...]

Unable to run grails test-app :cucumber

So I've looked through other peoples problems but they dont match what I'm seeing so thought I'd post it up to see if anyone else has had this issue and has a suggested solution
Im running a grails app in 2.3.5 and have cucumber 1.2.0
I've set up a really basic feature file in the functional folder that reads as follows: -
Feature:
As a user
If I enter the incorrect password I need a warning message
So I know i did something wrong
Scenario:
Given I enter the wrong login credentials
When I click sign in
Then Display a login error
Now I know this shouldn't work as yet but Im going one step at a time to see the process as Im new to cucumber and grails.
The app runs fine if I use the command
grails run-app -Dgrails.server.port.http=8090
If I then try running the cucumber test via
grails test-app :cucumber (with or without the port specification above) I get the following explosion...
Configuring Shiro ...
Shiro Configured
| Error 2017-03-15 08:28:35,222 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing the application: null
Message: null
Line | Method
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . . . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,247 [localhost-startStop-1] ERROR context.GrailsContextLoader - Error initializing Grails: null
Message: null
Line | Method
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . . . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,251 [localhost-startStop-1] ERROR [localhost].[/test] - Exception sending context initialized event to listener instance of class org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener
Message: Error executing bootstraps; nested exception is java.lang.NullPointerException
Line | Method
->> 262 | run in java.util.concurrent.FutureTask
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
Caused by NullPointerException: null
->> 2076 | contains in java.lang.String
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 207 | canAutoMigrate in grails.plugin.databasemigration.MigrationUtils
| 43 | autoRun . in grails.plugin.databasemigration.MigrationRunner
| 87 | doCall in DatabaseMigrationGrailsPlugin$_closure2
| 262 | run . . . in java.util.concurrent.FutureTask
| 1145 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 615 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 745 | run in java.lang.Thread
| Error 2017-03-15 08:28:35,271 [localhost-startStop-1] ERROR core.StandardContext - Error listenerStart
| Error 2017-03-15 08:28:35,280 [localhost-startStop-1] ERROR core.StandardContext - Context [/myProject] startup failed due to previous errors
| Server running. Browse to http://localhost:8080/myProject
| Server stopped
| Error Fatal error running tests: No WebApplicationContext found: no ContextLoaderListener registered? (Use --stacktrace to see the full trace)
| Tests FAILED - view reports in /Users/me/Projects/myProject/target/test-reports
| Error Error executing script TestApp: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered? (Use --stacktrace to see the full trace)
I have 0 idea what any of this means and googling any of it with a grails/cucumber context doesnt seem to really bring anything of sense back, any suggestions or questions welcome!
This is the content of my bootstrap.groovy file if that makes things any clearer, intellij doesn't register anything in here as broken just a few variables not being used...
import org.apache.shiro.crypto.hash.Sha256Hash
import uk.co.test.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class BootStrap {
def queueService
def init = { servletContext ->
def adminRole = new ShiroRole(name: "admin")
adminRole.addToPermissions("admin:*:*")
adminRole.save()
def userRole = new ShiroRole(name: "user")
userRole.addToPermissions("application:*:*")
userRole.addToPermissions("assertion:*:*")
userRole.addToPermissions("auth:*:*")
userRole.addToPermissions("displayResult:*:*")
userRole.addToPermissions("event:*:*")
userRole.addToPermissions("executor:*:*")
userRole.addToPermissions("folderNode:*:*")
userRole.addToPermissions("form:*:*")
userRole.addToPermissions("interaction:*:*")
userRole.addToPermissions("manualTest:*:*")
userRole.addToPermissions("object:*:*")
userRole.addToPermissions("objectType:*:*")
userRole.addToPermissions("page:*:*")
userRole.addToPermissions("project:*:*")
userRole.addToPermissions("queue:*:*")
userRole.addToPermissions("release:*:*")
userRole.addToPermissions("result:*:*")
userRole.addToPermissions("test:*:*")
userRole.addToPermissions("testSet:*:*")
userRole.addToPermissions("user:*:*")
userRole.save()
def adminUser = new ShiroUser(username: "admin", passwordHash: new Sha256Hash("test").toHex())
adminUser.addToRoles(adminRole)
adminUser.addToRoles(userRole)
adminUser.save()
def nonAdminUser = new ShiroUser(username: "user", passwordHash: new Sha256Hash("test").toHex())
nonAdminUser.addToRoles(userRole)
nonAdminUser.save()
if (Interaction.list().size() == 0) {
def interaction = new Interaction('click')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'check text', alias: 'checkText')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'get attribute', alias: 'getAttribute')
interaction.save(failOnError: true)
interaction = new Interaction(name: 'enter text', alias: 'type')
interaction.save(failOnError: true)
interaction = new Interaction('select radio button')
interaction.save(failOnError: true)
interaction = new Interaction('select')
interaction.save(failOnError: true)
interaction = new Interaction('hover')
interaction.save(failOnError: true)
}
if (ObjectType.findAll().size() == 0) {
def firstType = new ObjectType(type: "button", typeSysCode: "BUTTON")
firstType.save()
def secondType = new ObjectType(type: "link", typeSysCode: "LINK")
secondType.save()
def thirdType = new ObjectType(type: "label", typeSysCode: "LABEL")
thirdType.save()
def fourthType = new ObjectType(type: "textbox", typeSysCode: "TEXTBOX")
fourthType.save()
}
if (Queue.list().size() == 0) {
def manualQueue = new Queue(name: "manual",
allowedTestTypes: [TestTypes.MANUAL.getValue()]
)
manualQueue.save(failOnError: true)
}
def sd = Executors.newSingleThreadScheduledExecutor()
sd.scheduleAtFixedRate(new QueueRunnable(), 10, 5, TimeUnit.SECONDS)
environments {
development {
def firstRelease
def secondRelease
if (Release.findAll().size() == 0) {
def firstProject
def secondProject
if (Project.findAll().size() == 0) {
firstProject = new Project(name: "d2c application")
firstProject.save(failOnError: true)
secondProject = new Project(name: "b2b application")
secondProject.save(failOnError: true)
} else {
firstProject = Project.findByName("d2c application")
secondProject = Project.findByName("b2b application")
}
if (Release.findAll().size() == 0) {
firstRelease = new Release(name: "d2c 1", project: firstProject)
firstRelease.save()
secondRelease = new Release(name: "d2c 2", parentRelease: Release.findByNameAndProject('d2c 1', firstProject), project: firstProject)
secondRelease.save()
def thirdRelease = new Release(name: "b2b 1", project: secondProject)
thirdRelease.save()
def fourthRelease = new Release(name: "b2b 2", parentRelease: Release.findByNameAndProject('b2b 1', secondProject), project: secondProject)
fourthRelease.save()
}
} else {
firstRelease = Release.get(1)
secondRelease = Release.get(2)
}
if (Object.findAll().size() == 0 && Page.findAll().size() == 0) {
def firstObject = new Object(name: "BBC welcome text",
idType: "css",
locatorValue: "h2.hp-banner__text",
type: ObjectType.get(2),
release: firstRelease,
objectVersion: 1,
objectNumber: 1,
interaction: Interaction.findByName('check text')
)
firstObject.save(failOnError: true)
def secondObject = new Object(name: "BBC news link",
idType: "css",
locatorValue: "li.orb-nav-news a",
type: ObjectType.get(1),
release: firstRelease,
objectVersion: 1,
objectNumber: 2,
interaction: Interaction.findByName('click')
)
secondObject.save(failOnError: true)
def thirdObject = new Object(name: "BBC news business link",
idType: "id",
locatorValue: "linky",
type: ObjectType.get(2),
release: firstRelease,
objectVersion: 1,
objectNumber: 3,
interaction: Interaction.findByName('click')
)
thirdObject.save(failOnError: true)
def firstPage = new Page(name: "BBC home",
pageNumber: 1,
pageVersion: 1,
release: firstRelease
)
firstPage.save(failOnError: true)
def secondPage = new Page(name: "BBC news",
pageNumber: 2,
pageVersion: 1,
release: firstRelease
)
secondPage.save(failOnError: true)
def firstPageObject = new PageObject(object: firstObject,
objectNumber: firstObject.objectNumber,
page: firstPage,
behaviour: "interact",
value: "Welcome to the BBC"
)
firstPageObject.save(failOnError: true)
def secondPageObject = new PageObject(object: secondObject,
objectNumber: secondObject.objectNumber,
page: firstPage,
behaviour: "interact"
)
secondPageObject.save(failOnError: true)
def thirdPageObject = new PageObject(object: thirdObject,
objectNumber: thirdObject.objectNumber,
page: secondPage,
behaviour: "interact"
)
thirdPageObject.save(failOnError: true)
firstPage.objects = [firstPageObject, secondPageObject]
firstPage.save(failOnError: true)
secondPage.objects = [thirdPageObject]
secondPage.save(failOnError: true)
}
}
}
}
def destroy = {
}
}

Test file download with Capybara and Cucumber

I am trying to test a download using Capybara and Cucumber.
The test steps look like:
When(/^I export to CSV$/) do
export_button = find("div.results-table input[type=\"submit\"]")
export_button.click
end
Then(/^I should be prompted to download the CSV$/) do
Capybara.current_driver = :webkit #switch driver so we can see the response_headers
page.response_headers['Content-Disposition'].should include("filename=\"transactions\"")
end
I had to add the capybara webkit driver in the middle of the test so that I can use the response_headers, but the response_headers seem to return an empty object. I am using the default driver before that because I need to click the button, but I wonder if switching drivers like this is why I am not getting anything in the response_header?
I have done it in my recent project as shown below
Given Download folder for export is empty
And Joe clicks "Download Csv" button
Then The contents of the downloaded csv should be:
|TEAM_ID | TEAM_EXTERNAL_ID | TYPE | REG_OPTION | TEAM_REG_BRACKET | RACE_NAME | WAVE | BIB | BRACKET | STATUS | TEAM_NAME | TEAM_TYPE | ATHLETE_COUNT | MIN_MEMBERS | MAX_MEMBERS | TEAM_MEMBERS |
| 8 | | TEAM | 10k Aggregate | N/A | 10k | Universal | 208 | Overall | DNF | Team 08 | Aggregate |0 | | | |
And the capybara for this cucumber will be like
Given(/^Download folder for export is empty$/) do
FileUtils.rm_rf('/home/vagrant/Downloads/')
end
And(/^(\S*) clicks "([^"]*)" button$/) do |user, arg|
button = find_button(arg)
button.click
end
And /^The contents of the downloaded csv should be:$/ do |table|
for i in 0..5
if(Dir.glob('/home/vagrant/Downloads/*.csv'))
break;
end
sleep(1); // if not found wait one second before continue looping
end
if(Dir.glob('/home/vagrant/Downloads/*.csv'))
Dir['/home/vagrant/Downloads/*'].each do |file_name|
arr = CSV.read(file_name, :col_sep => "\t", :row_sep => "\r\n", encoding: "UTF-16:UTF-8")
table.raw[0...table.raw.length].each_with_index do |row, row_index|
row.each_with_index do |value, index|
if arr[row_index][index] == nil
arr[row_index][index] = ""
end
if index == 1
else
puts "#{index}" + 'Value in table = ' + "#{value} + 'Value in file' + #{arr[row_index][index]}"
value.should eq arr[row_index][index]
end
end
end
end
else
puts "/home/vagrant/Downloads/*.csv file not found!"
end
end
Hope this resolves you problem for downloading CSV and verifying its contents too :)