Skip to content
Snippets Groups Projects
Unverified Commit 4e39c980 authored by Kris J. Becker's avatar Kris J. Becker Committed by GitHub
Browse files

isisdataeval - ISISDATA Evaluation and Verification (#5111)

* isisdataeval validates/verifies ISISDATA (new)

This new application will evaluate all the files in an ISISDATA local installation for a valid kernel configuration and verify content

* Updated change log for isisdataeval

* Fixed typo in the XML doc

* Correct/updated documentation

* isisdataeval corrections/improvements and docs

This commit updates documentation base upon code review.

Some additional modifications were made to code to clean/clarify some processing and ensure special cases are identified.

Added the VERIFY parameter as its not very straight forward if you don’t add the right parameter (need to hash files to find bad filenames). This option will not require any output files to run both validation (always ran) and verification (optional).

* isisdataeval tools and documentation

The isisdata_mockup.py tool is provide to create an ISISDATA mockup to test the application. This submission documents the process to set up testing in the ISIS Google Test environment.

* isisdataeval add tests, data and ISISDATA mockup fixture

* Add all of isisdataeval ISISDATA mockup for tests

This directory contains a minimal configuration to provide testing for isisdataeval. Note that the total size of all these files is about 120K. See the README.md in ISIS3/isis/src/system/apps/isisdataeval/tools for details on how this data is created.

* isisdataeval tests must keep ignored files

There are some cube files and other files that end up being excluded in .gitignore. An entry was added that included all the files in this commit.
parent f13a7923
No related branches found
No related tags found
No related merge requests found
Showing
with 4213 additions and 1 deletion
...@@ -58,6 +58,9 @@ install/ ...@@ -58,6 +58,9 @@ install/
!isis/tests/data/near/msi2isis/*.lbl !isis/tests/data/near/msi2isis/*.lbl
!isis/tests/data/near/msicamera/*.cub !isis/tests/data/near/msicamera/*.cub
# Ensure the contents of ISISDATA mockup tests are preserved
!isis/tests/data/isisdata/mockup/**/*
# Ignore vs code # Ignore vs code
.vscode .vscode
......
...@@ -55,6 +55,7 @@ release. ...@@ -55,6 +55,7 @@ release.
### Added ### Added
- Added LatLonGrid Tool to Qview to view latitude and longitude lines if camera model information is present. - Added LatLonGrid Tool to Qview to view latitude and longitude lines if camera model information is present.
- Added a new application, _isisdataeval_, that validates/verifies ISISDATA installations and aids in the development and management of this resource. Users can use _isisdataeval_ to help resolve runtime problems related to ISIS kernels and calibration processing. In fact, it is designed to be used on any directory as it will create a detailed install volume inventory with file/volume hashes and is not restricted to ISIS use. [#5110](https://github.com/USGS-Astrogeology/ISIS3/issues/5110) [#5111](https://github.com/USGS-Astrogeology/ISIS3/pull/5111)
### Deprecated ### Deprecated
......
This diff is collapsed.
This diff is collapsed.
ifeq ($(ISISROOT), $(BLANK))
.SILENT:
error:
echo "Please set ISISROOT";
else
include $(ISISROOT)/make/isismake.apps
endif
\ No newline at end of file
/** This is free and unencumbered software released into the public domain.
The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/
/* SPDX-License-Identifier: CC0-1.0 */
#include "isisdataeval.h"
#include <array>
#include <vector>
#include <tuple>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <QString>
#include <QStringList>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
#include <QIODevice>
#include <QCryptographicHash>
#include "Application.h"
#include "FileName.h"
#include "IException.h"
#include "IsisDataModel.h"
#include "IString.h"
#include "iTime.h"
#include "Preference.h"
#include "Process.h"
#include "Progress.h"
#include "Pvl.h"
#include "PvlKeyword.h"
#include "PvlGroup.h"
#include "UserInterface.h"
namespace Isis {
// Might be able to use brackets here but the main may not be callable
// because its not in the Isis namespace. This should suffice.
using namespace Data;
//********************************************************************
// Helper functions and datatypes
//********************************************************************
/** Struct to capture inventory counts */
struct validation_counts {
validation_counts() {
m_missing = m_empty = m_symlinks = m_externals = m_errors = 0;
}
~validation_counts() { }
inline int sum() const {
int total = m_missing + m_empty + m_symlinks + m_externals + m_errors;
return ( total );
}
int m_missing;
int m_empty;
int m_symlinks;
int m_externals;
int m_errors;
};
typedef struct validation_counts ValidationCounts;
/** Add log Group to log file and console for backward compatability */
inline void db_addLogGroup( Pvl *log, PvlGroup &group ) {
// Report translations...
// Emulates: pvl->addLogGroup( group );
log->addGroup( group );
Application::Log( group );
return;
}
/** Report evaluation data consistently */
inline void report_issues( std::ostream &db_os,
const Data::DBFileDispositionList &db_status,
ValidationCounts &counts ) {
if ( db_status.size() > 0) {
db_os << "status, filespec, sourcespec, source, target, category" << std::endl;
for ( auto const &db_file : db_status ) {
QString v_status = db_file.name().toLower();
db_os << v_status << ","
<< db_file.key() << ","
<< db_file.datum().name() << ","
<< db_file.datum().expanded() << ","
<< db_file.datum().target() << ","
<< db_file.status()
<< std::endl;
if ( "missing" == v_status ) counts.m_missing++;
if ( "empty" == v_status ) counts.m_empty++;
if ( "symlink" == v_status ) counts.m_symlinks++;
if ( "external" == v_status ) counts.m_externals++;
if ( "error" == v_status ) counts.m_errors++;
}
}
}
//*******************************************************************
// isisdataeval main
//*******************************************************************
void isisdataeval( UserInterface &ui, Pvl *log ) {
Process eval_proc;
// Load any preferences file if requested. Note this is the same as adding
// adding a "-pref=PREFERENCES" except this logs the preferences file used.
if ( ui.WasEntered( "PREFERENCES" ) ) {
Preference::Preferences().Load( ui.GetAsString( "PREFERENCES" ) );
}
// Get a reference to the DataDirectory group for translations
PvlGroup &prefdir = Preference::Preferences().findGroup("DataDirectory");
// Determine the DATADIR to evaluate
QString datadir = ui.GetString( "DATADIR" );
FileName file_datadir( datadir );
DBFileStatus f_info( datadir );
QString dataroot = datadir;
std::cout << std::endl;
std::cout << "DATAROOT = " << f_info.original() << std::endl;
std::cout << "DATAROOT = " << f_info.expanded() << std::endl;
if ( !f_info.isDirectory() ) {
throw IException( IException::User,
"DATADIR (" + datadir + ") is not a directory!",
_FILEINFO_ );
}
// Get the DataDirectory from the Preferences file
FileName isisdata( "$ISISDATA" );
std::cout << std::endl;
std::cout << "ISISDATA = " << isisdata.expanded() << std::endl;
// Now reset ISISDATA if requested by user
if ( ui.WasEntered( "ISISDATA" ) ) {
isisdata = ui.GetAsString("ISISDATA");
PvlKeyword iroot( "ISISDATA", isisdata.expanded() );
prefdir.addKeyword( iroot, PvlContainer::Replace );
std::cout << "ISISDATA = " << isisdata.expanded() << std::endl;
std::cout << "ISISDATA reset by user!" << std::endl;
std::cout << std::endl;
}
// Report translations...
// pvl->addLogGroup( prefdir );
db_addLogGroup( log, prefdir );
//*******************************************************************
// Process DATADIR which will collect the inventory and evaluate
// the kernel kernel_????.db and kernel_????.conf
// Traverse DATADIR using ISISDATA as $ISISDATA volume translations.
//*******************************************************************
IsisDataModel v_isisdatadir( datadir, isisdata.expanded() );
// Run the evaluation of the kernel db/conf configuration
BigInt t_install_size = v_isisdatadir.evaluate();
double t_volume_size = (double) t_install_size / (1024.0 * 1024.0 * 1024.0);
// Collect evaluation data
size_t s_dirs; // total directories in dataroot
BigInt t_allfiles = v_isisdatadir.allFilesCount( &s_dirs );
BigInt t_dirs = s_dirs;
BigInt t_files = t_allfiles - t_dirs;
// The counts for *.db and *.conf files found
BigInt t_kerneldbs = v_isisdatadir.dbCount();
BigInt t_configs = v_isisdatadir.configCount();
// Problem areas
DBFileDispositionList kernel_status;
int v_bad = v_isisdatadir.validate( kernel_status );
std::cout << "\nValidation Complete..." << v_bad << " issues found!" << std::endl;
// Report kernel validation status to console
ValidationCounts inventory_counts;
report_issues(std::cout, kernel_status, inventory_counts );
// Generate the result log
std::cout << std::endl;
PvlGroup results("Results");
results.addKeyword( PvlKeyword( "ISISDATA", isisdata.expanded() ) );
results.addKeyword( PvlKeyword( "DATADIR", datadir ) );
results.addKeyword( PvlKeyword( "EmptyKernelDBs", toString( inventory_counts.m_empty ) ) );
results.addKeyword( PvlKeyword( "MissingKernelDBs", toString( inventory_counts.m_missing ) ) );
results.addKeyword( PvlKeyword( "SymlinkKernelFiles", toString( inventory_counts.m_symlinks ) ) );
results.addKeyword( PvlKeyword( "ExternalKernelFiles", toString( inventory_counts.m_externals ) ) );
results.addKeyword( PvlKeyword( "ErrorKernelFiles", toString( inventory_counts.m_errors ) ) );
results.addKeyword( PvlKeyword( "TotalDBConfigFiles", toString( t_configs ), "conf" ) );
results.addKeyword( PvlKeyword( "TotalKernelDBFiles", toString( t_kerneldbs ), "db" ) );
results.addKeyword( PvlKeyword( "TotalDirectories", toString( t_dirs ) ) );
results.addKeyword( PvlKeyword( "TotalDataFiles", toString( t_files ) ) );
results.addKeyword( PvlKeyword( "TotalInstallSize", toString( t_install_size ), "bytes" ) );
results.addKeyword( PvlKeyword( "TotalVolumeSize", toString( t_volume_size ), "GB" ) );
// If users wants kernel issues reported, write it out here
if ( ui.WasEntered( "TOISSUES" ) ) {
FileName toissues = ui.GetFileName( "TOISSUES" );
// Only write the file if there are missing files
if ( kernel_status.size() > 0 ) {
std::ofstream os;
os.open( toissues.expanded().toLatin1().data(), std::ios::out );
if (!os ) {
QString mess = "Unable to open/create " + toissues.expanded();
throw IException( IException::User, mess, _FILEINFO_ );
}
// Write the results
ValidationCounts issue_counts;
report_issues( os, kernel_status, issue_counts );
// All done...
os.close();
}
}
//*******************************************************************
// Process all the data found in DATADIR. If DATADIR = ISISDATA,
// the complete ISISDATA install is validated.
//*******************************************************************
// If user wants to validate the whole of DATADIR, this is it.
const bool needInventory = ui.WasEntered( "TOINVENTORY" );
const bool doVerify = ui.GetBoolean( "VERIFY" );
// Set up default hash and determine if requested by user
QCryptographicHash::Algorithm hash_algorithm = QCryptographicHash::Md5;
QString hashtype = ui.GetString( "HASH" ).toLower();
const bool needHash = ( "nohash" != hashtype );
// Either case will kick off the inventory.
if ( needInventory || needHash || doVerify ) {
// Check if user wants detailed log of DATADIR
QString inventory_file( "/dev/null" );
if ( needInventory ) {
FileName toinventory = ui.GetFileName( "TOINVENTORY" );
inventory_file = toinventory.expanded();
}
if ( needHash ) {
// Get the algorithm of choice
if ( "md5" == hashtype ) hash_algorithm = QCryptographicHash::Md5;
if ( "sha1" == hashtype ) hash_algorithm = QCryptographicHash::Sha1;
if ( "sha256" == hashtype ) hash_algorithm = QCryptographicHash::Sha256;
}
// Only write the file if there are missing files
ValidationCounts error_counts_t;
if ( v_isisdatadir.size() > 0 ) {
std::ofstream os;
os.open( inventory_file.toLatin1().data(), std::ios::out );
if (!os ) {
QString mess = "Unable to open/create " + inventory_file;
throw IException( IException::User, mess, _FILEINFO_ );
}
// Create the header output from the first file in the inventory.
// Note its assured to exist. Add the hash field if requested.
QStringList header = v_isisdatadir.allfiles().cbegin()->header();
// Set the hashtag
QString hashtag( hashtype );
if ( needHash ) {
hashtag = hashtype + "hash";
header.append( hashtag );
}
// Write header to output file
os << header.join(",") << std::endl;
std::cout << "Running inventory ..." << std::endl;
Progress v_progress;
v_progress.SetText("inventory+"+hashtag);
v_progress.SetMaximumSteps( v_isisdatadir.size() );
v_progress.CheckStatus();
BigInt n_symlinks = 0;
QCryptographicHash volume_hash( hash_algorithm );
// Determine size (MB) of file buffer for hashing only if requested
std::unique_ptr<char[]> file_data;
qint64 HashBufferSizeBytes = 1024 * 1024 * 256; // Default size
if ( needHash ) {
HashBufferSizeBytes = 1024 * 1024 * ui.GetInteger("HASHBUFFER");
// Consistent with the Qt 5.15 API
file_data.reset( new char[HashBufferSizeBytes] );
}
DBFileDispositionList inventory_errors;
const qint64 MaxBytesToRead = HashBufferSizeBytes;
for ( auto const &dbfile : v_isisdatadir.allfiles() ) {
if ( !dbfile.isDirectory() ) {
// Check for symbolic links
if ( dbfile.isSymbolicLink() ) {
n_symlinks++;
QString symtarget = dbfile.info().symLinkTarget();
DBFileStatus symfile( symtarget );
// Report symlink
inventory_errors.push_back( DBFileDisposition( "symlink", dbfile.name(), symfile, "inventory" ) );
if ( !symfile.exists() ) {
inventory_errors.push_back( DBFileDisposition( "missing", dbfile.info().symLinkTarget(), dbfile, "nosymlink" ) );
}
else {
if ( !v_isisdatadir.allfiles().contains( symfile.original() ) ) {
inventory_errors.push_back( DBFileDisposition( "external", symfile.name(), dbfile, "symlink" ) );
}
}
}
else {
// Create and write the values array from json object
// Don't terminate the row here in case hashing is needed
os << dbfile.values().join(",");
// If hashing has been requested, do it here. We are computing two
// hashes - one is individual file hash, the other is the complete
// volume hash. Otherwise, check the file for errors.
QFile v_file( dbfile.expanded() );
if ( needHash ) {
QCryptographicHash file_hash( hash_algorithm );
// File exists, lets open it and compute the hash
if ( !v_file.open( QIODevice::ReadOnly ) ) {
inventory_errors.push_back( DBFileDisposition( "error", dbfile.expanded(), dbfile, "openfailed" ) );
// Write a null as the hash
os << "," << db_null();
}
else {
// Read (in (1MB * HASHBUFFER) chunks) bytes and add to hashes
while ( !v_file.atEnd() ) {
qint64 nread = v_file.read(file_data.get(), MaxBytesToRead );
// Add to hashes
file_hash.addData( file_data.get(), nread );
volume_hash.addData( file_data.get(), nread );
}
// Write the file hash to the output file row
os << "," << QString::fromUtf8( file_hash.result().toHex() );
}
}
else {
// Check for existance of expanded version of file
if ( !v_file.exists() ) {
inventory_errors.push_back( DBFileDisposition( "error", dbfile.expanded(), dbfile, "badfilename" ) );
}
}
// Terminate the line and on to the next one
os << std::endl;
}
}
v_progress.CheckStatus();
}
// Report any issues found with inventory...
std::cout << "\nInventory Complete..." << inventory_errors.size() << " issues found!" << std::endl;
if ( inventory_errors.size() > 0) {
report_issues( std::cout, inventory_errors, error_counts_t );
// If users wants the missing reported, write it out here
if ( ui.WasEntered( "TOERRORS" ) ) {
FileName toerrors = ui.GetFileName( "TOERRORS" );
// Only write the file if there are missing files
std::ofstream error_os;
error_os.open( toerrors.expanded().toLatin1().data(), std::ios::out );
if (!error_os ) {
QString mess = "Unable to open/create " + toerrors.expanded();
throw IException( IException::User, mess, _FILEINFO_ );
}
// Write the results
ValidationCounts counts_t;
report_issues( error_os, inventory_errors, counts_t );
// All done...
error_os.close();
}
}
// Report results
results.addKeyword( PvlKeyword( "MissingInInventory", toString( error_counts_t.m_missing ) ) );
results.addKeyword( PvlKeyword( "SymlinkInInventory", toString( error_counts_t.m_symlinks ) ) );
results.addKeyword( PvlKeyword( "ExternalToInventory", toString( error_counts_t.m_externals ) ) );
results.addKeyword( PvlKeyword( "ErrorInInventory", toString( error_counts_t.m_errors ) ) );
if ( needHash ) {
QByteArray v_hash_data = volume_hash.result();
QString volume_hash_str = QString::fromUtf8( v_hash_data.toHex() );
BigInt hbsize = HashBufferSizeBytes;
results.addKeyword( PvlKeyword( "HashBufferSize", toString(hbsize), "bytes" ) );
results.addKeyword( PvlKeyword( "TotalVolumeHash", volume_hash_str, hashtype ) );
}
// All done...
os.close();
}
}
// Final log
// pvl->addLogGroup( results );
db_addLogGroup( log, results );
eval_proc.Finalize();
return;
}
} // namespace Isis
#ifndef isisdataeval_h
#define isisdataeval_h
/** This is free and unencumbered software released into the public domain.
The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/
/* SPDX-License-Identifier: CC0-1.0 */
#include "Pvl.h"
#include "UserInterface.h"
namespace Isis {
extern void isisdataeval( UserInterface &ui, Pvl *log );
}
#endif
This diff is collapsed.
/** This is free and unencumbered software released into the public domain.
The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/
/* SPDX-License-Identifier: CC0-1.0 */
#include "Isis.h"
#include "isisdataeval.h"
#include "Application.h"
#include "Pvl.h"
using namespace Isis;
void IsisMain() {
UserInterface &ui = Application::GetUserInterface();
Pvl appLog;
isisdataeval(ui, &appLog);
}
# <a name="#testingisisdataeval">ISISDATA Mockup Procedures for Testing isisdataeval</a>
Proper, thorough testing of ISIS application `isisdataeval` is difficult due to the requirements of having a stable and flexible ISISDATA directory structure to test with. It is unfeasible to rely on the real $ISISDATA due to its volitile and every changing content. One solution is to create a mockup of the ISISDATA directory but mimimize the resources to emulate a real, functioning ISISDATA installation. The system presented here generates a complete ISISDATA directory structure at a signification fraction of the actual dataset. By careful selective culling of many of the existing files in the selection mission datasets, it creates a real time snapshot of ISISDATA to help test `isisdataeval`.
The ISISDATA mockup system is a complete copy of every directory and every file in an existing ISISDATA install. However, the contents of every file has been replaced with information about that file, keeping the size of every file to about 300 bytes each. Here is the format of a file prepared by this system:
`cat isisdatamockup/base/kernels/spk/de118.bsp`
```
{
"source": "$ISISDATA/base/kernels/spk/de118.bsp",
"filesize": 4097024,
"createtime": "2022-08-12T22:13:17.000000",
"modifiedtime": "2022-11-24T12:24:04.449174",
"md5hash": "24a225d8262be0e0a7140dd40c708428",
"sha256hash": "118774c31125cf0051faeb340532d03cab1b81adb63369db5842daefc1684a3c",
"sha1hash": "dd6071b1a47193fe7abd6e9fc9db808408ef0429"
}
```
The size of this file has been reduced to 376 bytes from 4,097,024 bytes. Each file will contain JSON text with details about the original file. The files size, creation and modified dates, and hash values for the md5, sha1 and sha256 hash algorithms computed from the contents of the file using Python tools - and independt. The hash values are expressly provided to provide comparisons of the Qt algorithms used in `isisdataeval`. Note it is possible, but cannot be guaranteed, the _source_ for the file will exists in every ISISDATA install, or even be the same file. But this is a good thing to test.
# <a name="#isisdatamockuptool">ISISDATA Mockup Tool - isisdata_mockup.py</a>
A tool has been provided with the `isisdataeval` application that generates ISISDATA mockups for this and potentially other purposes. This Python tool will convert an ISISDATA installation into a mockup that is suitable to test the database lookup system and verify the contents and structure of mission kernel configurations in $ISISDATA. However, it has been generalized to use for any directory structure. Here is the application documentation:
`isisdata_mockup.py -h`
```
usage: isisdata_mockup.py [-h] --isisdata ISISDATA --outpath OUTPATH [--ghostdir GHOSTDIR]
[--saveconfig] [--dryrun] [--verbose]
Convert ISISDATA directory to test format
optional arguments:
-h, --help show this help message and exit
--isisdata ISISDATA ISISDATA directory root
--outpath OUTPATH NEW ISISDATA directory to create
--ghostdir GHOSTDIR Replaces the --isisdata path with this string to ghost the actual input
directory path
--saveconfig, -s Retain *.db, *.conf files rather than replace with processs info
--dryrun, -n Only print actions but do not execute
--verbose, -v Verbose output
isisdata_mockup.py will create a copy of all the files found in the directory specified by
the --isisdata parameter. All files and directories contained in --isisdata will
be copied to the --outpath destination, which specifies a new directory. This
directory will be created if it does not exist.
All *.db and *.conf files are copied as is, fully intact. Also needed to use this
mock up of ISISDATA is the NAIF LSK. This LSK kernel is always loaded by the iTime
class to concert UTC and Et times. Otherwise, all other files encountered will
be created but the contents are replaced by information regarding the --isisdata
source file. This information includes the original file opath, creation and
modification dates in UTC format, the size of the file and its hash values.
This app sets up a full data directory structure that mimics the contents of
ISISDATA (or any directory for that matter). The size of the file, its creation
and last modification dates and the md5, sha1 and sha256 hash values are created
in a dict which is then written to the new output file if its not a special ISIS
kernel db/conf file or LSK.
Finally, by setting --ghostdir '$ISISDATA', this now provides a connection to
the source file in the ISISDATA directory. This can be used to compare hash values
compute by other sources.
Example:
To provide a full mock up of ISISDATA directory:
isisdata_mockup.py --saveconfig --isisdata /opt/isis/data --outpath $PWD/mockisisdata --ghostdir '$ISISDATA'
Author: Kris J. Becker, University of Arizona
kbecker@orex.lpl.arizona.edu
History 2023-03-15 Kris Becker - Original verison
```
You can also choose to process only a single directory, as shown in the following example:
```
isisdata_mockup.py --saveconfig --isisdata /opt/isis/data/voyager1 --outpath $PWD/mockisisdata/voyager1 --ghostdir '$ISISDATA/voyager1'
```
Processing times can be significant since this script is computing 3 different hash values per file.
# <a name="#isisdatamockupinstall">ISISDATA Mockup Test Data Preparation</a>
With this tool and the files listed in `isisdataeval_isisdata_mockup_files.lis`, the test for isisdataeval can be recreated from any ISISDATA installation. Note that from time to time, the files used in this ISISDATA test could change which would cause failures. Here are the commands to create the `isisdataeval` test ISISDATA mockup directory - from the Git install directory:
```
# Create the test data area for isisdata
cd ISIS3/isis/test/isisdata
mkdir -p mockup mockprocessing
# Produce the mockup data. Its assumed isisdata_mockup.py is in a runtime path.
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/base --outpath mockprocessing/isisdatamockup/base --ghostdir '$ISISDATA/base'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/hayabusa --outpath mockprocessing/isisdatamockup/hayabusa --ghostdir '$ISISDATA/hayabusa'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/smart1 --outpath mockprocessing/isisdatamockup/smart1 --ghostdir '$ISISDATA/smart1'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/voyager1 --outpath mockprocessing/isisdatamockup/voyager1 --ghostdir '$ISISDATA/voyager1'
# Copy/install the desired files for the test
rsync -av --files-from=isisdataeval_isisdata_mockup_files.lis mockprocessing/isisdatamockup/ mockup/
/bin/rm -rf mockprocessing
# Run an inventory test for the mockup
isisdataeval isisdata=mockup datadir=mockup toinventory=isisdata_mockup_inventory.csv toissues=isisdata_mockup_issues.csv toerrors=isisdata_mockup_errors.csv hash=md5
```
# <a name="#isisdatamockuptests">Running ISISDATA Mockup Tests</a>
Once the test data is installed, the contents ./ISIS3/isis/tests/data/isisisdata/mockup will contain the test data created above. To explicitly run the `isisdataeval` tests, use `ctest -R IsisData`. If an error occurs, rerun with the command `ctest --rerun-failed --output-on-failure` to get specific information about which tests failed and why.
Note that during this test, the contents of files with less than 102400 bytes will have all three hash values compute in the tests and compared with the values stored in hash keywords, _md5hash_, _sha1hash_ and _sha256hash_ for an external validation hashing. Note also that the all files $ISISDATA/base/kernels/lsk are retained since Isis::iTime requires an LSK and it always loads one from $ISISDATA/base/lsk/naif????.tls.
#!/usr/bin/env python
# coding: utf-8
# In[ ]:
import time
import calendar
import datetime
import math
import os
import io
import pathlib
import hashlib
import re
import glob
import fnmatch
import shutil
import json
from collections import OrderedDict
import argparse
# In[ ]:
def parse_arguments():
"""
Parse command line arguments for the application
Parameters
----------
none
Returns
-------
Namespace object
This object contains parameters that were gathered from the users
command line. It can be converted to dict using vars(args).
"""
full_doc = '''\
%(prog)s will create a copy of all the files found in the directory specified by
the --isisdata parameter. All files and directories contained in --isisdata will
be copied to the --outpath destination, which specifies a new directory. This
directory will be created if it does not exist.
All *.db and *.conf files are copied as is, fully intact. Also needed to use this
mock up of ISISDATA is the NAIF LSK. This LSK kernel is always loaded by the iTime
class to concert UTC and Et times. Otherwise, all other files encountered will
be created but the contents are replaced by information regarding the --isisdata
source file. This information includes the original file opath, creation and
modification dates in UTC format, the size of the file and its hash values.
This app sets up a full data directory structure that mimics the contents of
ISISDATA (or any directory for that matter). The size of the file, its creation
and last modification dates and the md5, sha1 and sha256 hash values are created
in a dict which is then written to the new output file if its not a special ISIS
kernel db/conf file or LSK.
Finally, by setting --ghostdir '$ISISDATA', this now provides a connection to
the source file in the ISISDATA directory. This can be used to compare hash values
compute by other sources.
Example:
To provide a full mock up of ISISDATA directory:
%(prog)s --saveconfig --isisdata /opt/isis4/data --outpath $PWD/mockisisdata --ghostdir '$ISISDATA'
Author: Kris J. Becker, University of Arizona
kbecker@orex.lpl.arizona.edu
History 2023-03-15 Kris Becker - Original verison
'''
# Set to None for notebook mode or True for applicaton
is_app = True
if is_app is True:
parser = argparse.ArgumentParser(description="Convert ISISDATA directory to test format",
add_help=True,
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=full_doc)
parser.add_argument('--isisdata', help="ISISDATA directory root",
required=True, action='store', default=None)
parser.add_argument('--outpath', help="NEW ISISDATA directory to create",
required=True, action='store', default=None)
parser.add_argument('--ghostdir',
help="Replaces the --isisdata path with this string to ghost the actual input directory path ($ISISDATA is highly recommended)",
required=False, action='store', default=None)
parser.add_argument('--saveconfig','-s',
help='Retain *.db, *.conf files rather than replace with processs inf (for isisdataeval testing)',
action='store_true')
parser.add_argument('--dryrun','-n',help='Only print actions but do not execute', action='store_true')
parser.add_argument('--verbose','-v',help='Verbose output', action='store_true')
args = parser.parse_args()
else:
# This is ran when ( is_app is None )
isisdata = '/opt/isis/data/base/dems'
outpath = '/tmp/MOCKISISDATA/base/dems'
ghostdir = '$ISISDATA/base/dems'
saveconfig = True
dryrun = True
verbose = True
args = argparse.Namespace(isisdata=isisdata, outpath=outpath, ghostdir=ghostdir,
saveconfig=saveconfig, dryrun=dryrun, verbose=verbose)
return args
# In[ ]:
def compute_hash( filepath, method='md5', dryrun=False, verbose=False, **kwargs):
"""
Compute md5, sha1 or sha256 hashes from a file
Parameters
----------
filepath : string
Source file to conpute hash values for
method : string
Specifies the hash algorithm to apply:
md5, sha1 or sha256
Returns
-------
string
Returns the hex value of the compute hash for the file
"""
if 'sha256' in method:
hasher = hashlib.sha256()
elif 'sha1' in method:
hasher = hashlib.sha1()
else:
hasher = hashlib.md5()
with open( filepath, "rb" ) as fb:
for data in iter( lambda: fb.read(4096), b""):
hasher.update( data )
return hasher.hexdigest()
# In[ ]:
def preserve_file_contents( filepath, **kwargs ):
"""
Determine if the file content should be preserved. This particular
implemenatation satisfies requirements for mocking the ISISDATA
directly to be used for testing of isisdataeval.
This function preserves all files that end with a .db suffix. These
are ISIS kernel databases.
Files that have a .conf suffix are also ISIS kernel config file.
However, MRO/HiRISE calibration application uses files that end with
the .conf suffix.
And the $base/kernels/lsk LSK kernels are preserved. This is because
isisdataeval uses the ISIS iTime class to convert UTC times to ephemeris
times and vice versa.
All other file types are not preserved.
Parameters
----------
filepath : Path object
Source file to check for perservation
kwargs : args
Additional parameters
Returns
-------
bool
Returns True if the conditions to preserve the contents is met.
Otherwise, returns False.
"""
if filepath.suffix == '.db': return True
if filepath.suffix == '.conf':
if 'kernels' in filepath.as_posix(): return True
if 'base/kernels/lsk/naif00' in filepath.as_posix(): return True
# All other cases
return False
# In[ ]:
def main():
"""
Read ISISDATA contents and create a new directory structure
that maps the files but replaces contents with file information
for testing purposes. Files that end with ".db" or ".conf" file
suffixes are copied as is. All other files are replaced with
data file info.
Parameters
----------
See parse_arguments()
Returns
-------
None
"""
# Get the application parameters as provided by user
args = parse_arguments()
kwargs = vars(args)
# Consolidate some parameters
verbose = args.verbose
dryrun = args.dryrun
report = verbose or dryrun
isisdatadir = args.isisdata
ghostdir = args.ghostdir
outpath = args.outpath
saveconfig = args.saveconfig
allfiles = sorted( pathlib.Path( isisdatadir ).glob('**/*') )
if report: print("\nTotalFilesDirsFound: ", len(allfiles) )
missing = [ ]
for fpath in allfiles:
if report: print("\n*** Processing: ", fpath.as_posix() )
isisdatapos = fpath.as_posix().find( isisdatadir )
# Ghost the input dir if requested
if ghostdir is not None:
isisfile = fpath.as_posix().replace( isisdatadir, ghostdir, 1 )
else:
isisfile = fpath.as_posix()
if isisdatapos != 0:
if report: print("FileNotInIsisDataIgnored: ", fpath.as_posix() )
missing.append( fpath.as_posix() )
else:
jsondata = OrderedDict()
jsondata["source"] = isisfile
newisisdata = pathlib.Path( fpath.as_posix().replace( isisdatadir, outpath, 1 ) )
# jsondata['source'] = newisisdata.as_posix()
if fpath.is_dir():
if not dryrun: newisisdata.mkdir( parents=True )
else: # its a real file
outdir = pathlib.Path( newisisdata.parent )
finfo = fpath.stat()
create_ts = os.path.getctime( fpath.as_posix() )
modified_ts = finfo.st_mtime
# This is actually needed on some systems
if modified_ts < create_ts:
create_ts, modified_ts = modified_ts, create_ts
# This one does not work on Linux systems (gotta be root to get the correct datetime!)
#createtime = datetime.datetime.fromtimestamp( finfo.st_birthtime, tz=datetime.timezone.utc ).strftime('%Y-%m-%dT%H:%M:%S.%f')
createtime = datetime.datetime.fromtimestamp( create_ts, tz=datetime.timezone.utc ).strftime('%Y-%m-%dT%H:%M:%S.%f')
modifiedtime = datetime.datetime.fromtimestamp( modified_ts, tz=datetime.timezone.utc ).strftime('%Y-%m-%dT%H:%M:%S.%f')
# Compute the file hashes
md5hash = compute_hash( fpath.as_posix(), method='md5', **kwargs)
sha256hash = compute_hash( fpath.as_posix(), method='sha256', **kwargs)
sha1hash = compute_hash( fpath.as_posix(), method='sha1', **kwargs)
# The rest of the data for this file
jsondata["filesize"] = finfo.st_size
jsondata["createtime"] = createtime
jsondata["modifiedtime"] = modifiedtime
jsondata["md5hash"] = md5hash
jsondata["sha256hash"] = sha256hash
jsondata["sha1hash"] = sha1hash
if report:
print( json.dumps( jsondata, indent=4 ) )
if not outdir.exists():
if report: print("CreatingDir: ", outdir.as_posix() )
if not dryrun: outdir.mkdir(parents=True)
# There are also *.conf in $ISISDATA/mro/calibration so must exclude copying of those files
# isisdataeval requires that the LSK be valid (for time conversions) so preserve those kernels
if saveconfig and preserve_file_contents( fpath, **kwargs):
if report: print("CopyTo: ", newisisdata.as_posix() )
if not dryrun: shutil.copy( fpath.as_posix(), newisisdata.as_posix() )
else:
if report: print("WriteDataTo: ", newisisdata.as_posix() )
if not dryrun: newisisdata.write_text( json.dumps( jsondata, indent=4 ) )
# In[ ]:
# Do it!
if __name__ == '__main__':
main()
#include <cmath>
#include <algorithm>
#include "QTemporaryDir"
#include "IsisDataFixtures.h"
#include "IsisDataModel.h"
#include "isisdataeval.h"
#include "CSVReader.h"
#include "TempFixtures.h"
#include "TestUtilities.h"
#include "gtest/gtest.h"
using namespace Isis;
inline CSVReader load_isisdata_csv( const QString &csvfile ) {
const bool hasHeader = true;
return ( CSVReader( csvfile, hasHeader ) );
}
inline QStringList row_from_csv( const CSVReader::CSVAxis &row ) {
QStringList rdata;
for ( int i = 0 ; i < row.dim1() ; i++ ) {
rdata.append( row[i].simplified() );
}
return ( rdata );
}
inline QStringList get_row( const CSVReader::CSVTable &table, const int rindex = 0 ) {
return ( row_from_csv( table[rindex] ) );
}
inline QStringList get_header( const CSVReader &csv ) {
return ( row_from_csv( csv.getHeader() ) );
}
static QString APP_XML = FileName("$ISISROOT/bin/xml/isisdataeval.xml").expanded();
TEST_F( IsisDataInventory, ConfirmIsisDataInventory ) {
Pvl appLog;
const QString isisinventoryfile = tempDir.path() + "/isisdata_inventory.csv";
const QString isiserrorsfile = tempDir.path() + "/isisdata_errors.csv";
const QString isisissuesfile = tempDir.path() + "/isisdata_issues.csv";
QVector<QString> args = {"isisdata=" + isisdatadir(),
"datadir=" + isisdatadir(),
"verify=true",
"toinventory=" + isisinventoryfile,
"toissues=" + isisissuesfile,
"toerrors=" + isiserrorsfile };
UserInterface options(APP_XML, args);
try {
isisdataeval(options, &appLog);
}
catch (IException &e) {
FAIL() << "Unable to process ISISDATA directory: " << isisdatadir().toStdString() << std::endl;
}
// Get Results group from output
const PvlGroup &results = appLog.findGroup( "Results" );
EXPECT_EQ( (int) results["TotalDataFiles"], this->size() );
EXPECT_EQ( (int) results["EmptyKernelDBs"], 1 );
EXPECT_EQ( (int) results["MissingKernelDBs"], 4 );
EXPECT_EQ( (int) results["ExternalKernelFiles"], 3 );
EXPECT_EQ( (int) results["SymlinkKernelFiles"], 0 );
EXPECT_EQ( (int) results["TotalDBConfigFiles"], 1 );
EXPECT_EQ( (int) results["TotalKernelDBFiles"], 27 );
EXPECT_EQ( (int) results["TotalDirectories"], 43 );
EXPECT_EQ( (int) results["TotalDataFiles"], 176 );
EXPECT_EQ( (int) results["TotalInstallSize"], 118961);
// Load the inventory file
CSVReader csv_inventory = load_isisdata_csv( isisinventoryfile );
EXPECT_EQ( csv_inventory.rows() , this->size() );
int n_issues = (int) results["EmptyKernelDBs"] +
(int) results["MissingKernelDBs"] +
(int) results["ExternalKernelFiles"] +
(int) results["SymlinkKernelFiles"];
FileName issues( isisissuesfile );
if ( issues.fileExists() ) {
CSVReader csv_issues = load_isisdata_csv( isisissuesfile );
EXPECT_EQ( csv_issues.rows() ,n_issues );
// Now loop to determine if isisdataeval correctly identified the issues
int n_empty_found = 0;
int n_missing_found = 0;
int n_external_found = 0;
int n_symlinks_found = 0;
int n_errors_found = 0;
int n_undefined_found = 0;
QStringList issues_header = get_header ( csv_issues );
int status_t = issues_header.indexOf( "status" );
int filespec_t = issues_header.indexOf( "filespec" );
int error_n = csv_issues.rows();
for ( int i = 0 ; i < error_n ; i++ ) {
QStringList rowdata = get_row( csv_issues.getTable(), i );
const QString status = rowdata[status_t];
QString isisdata_filename = rowdata[filespec_t];
FileName fnFile( isisdata_filename );
// if ( fnFile.isVersioned() ) fnFile.highestVersion();
QFileInfo qfFile( fnFile.expanded() );
if ( "empty" == status ) {
n_empty_found++;
EXPECT_EQ ( (int) qfFile.size(), 0 );
}
else if ( "missing" == status ) {
n_missing_found++;
EXPECT_EQ( fnFile.fileExists(), false );
}
else if ( "external" == status ) {
n_external_found++;
}
else if ( "symlink" == status ) {
n_symlinks_found++;
}
else if ( "error" == status ) {
n_errors_found++;
}
else {
n_undefined_found++;
}
}
// Test for contents being consistent with reported status
EXPECT_EQ( (int) results["EmptyKernelDBs"], n_empty_found);
EXPECT_EQ( (int) results["MissingKernelDBs"], n_missing_found);
EXPECT_EQ( (int) results["ExternalKernelFiles"], n_external_found);
EXPECT_EQ( (int) results["SymlinkKernelFiles"], n_symlinks_found);
EXPECT_EQ( (int) results["ErrorKernelFiles"], n_errors_found);
EXPECT_EQ( n_undefined_found, 0);
}
// There are no errors for this case
FileName errors( isiserrorsfile );
EXPECT_EQ( errors.fileExists() , true );
if ( errors.fileExists() ) {
CSVReader csv_errors = load_isisdata_csv( isiserrorsfile );
EXPECT_EQ( csv_errors.rows() , (int) results["ErrorInInventory"]);
}
// Process the ISISDATA inventory
int nrows = std::min( (int) csv_inventory.rows(), (int) this->size() );
QStringList inv_header = get_header (csv_inventory );
int target_t = inv_header.indexOf( "target" );
for ( int i = 0 ; i < nrows ; i++ ) {
QStringList rowdata = get_row( csv_inventory.getTable(), i );
QString isisdata_filename = rowdata[target_t];
isisdata_filename.replace( isisdata_path() , "." );
EXPECT_EQ( inventory().contains( isisdata_filename ), true );
}
}
TEST_F( IsisDataInventory, CompareHashDataInIsisDataInventory ) {
const size_t MaxFileHashSize = 100 * 1024;
Pvl appLog;
QVector<QString> args = {"isisdata=" + isisdatadir(),
"datadir=" + isisdatadir(),
"verify=true" };
UserInterface options(APP_XML, args);
try {
isisdataeval(options, &appLog);
}
catch (IException &e) {
FAIL() << "Unable to process ISISDATA directory: " << isisdatadir().toStdString() << std::endl;
}
int n_md5_compared = 0;
int n_sha1_compared = 0;
int n_sha256_compared = 0;
// Gota do it this way if its NOT the only test run to find the real ISISDATA
PvlGroup &dataDir = Preference::Preferences(true).findGroup("DataDirectory");
if ( dataDir.hasKeyword( "ISISDATA") ) dataDir.deleteKeyword( "ISISDATA" );
IsisDataInventoryMap::const_iterator fileinfo = inventory().begin();
while ( fileinfo != inventory().end() ) {
if ( fileinfo.value().info().exists() ) {
const json_t &jdata = fileinfo.value().data();
QString source = QString::fromStdString( jdata["source"] );
// Not all of these files will exist in the currently available ISISDATA
// To save time only get the smaller ones as set above!
Data::DBFileStatus real_isis_file_info( source );
if ( real_isis_file_info.exists() && ( real_isis_file_info.size() < MaxFileHashSize ) ) {
int filesize = jdata["filesize"];
EXPECT_EQ( filesize, real_isis_file_info.size() );
if ( jdata.contains( "md5hash" ) ) {
QString md5hash = real_isis_file_info.hash( QCryptographicHash::Md5 ).toHex();
EXPECT_EQ( jdata["md5hash"], md5hash.toStdString() );
n_md5_compared++;
}
if ( jdata.contains( "sha1hash" ) ) {
QString sha1hash = real_isis_file_info.hash( QCryptographicHash::Sha1 ).toHex();
EXPECT_EQ( jdata["sha1hash"], sha1hash.toStdString() );
n_sha1_compared++;
}
if ( jdata.contains( "sha256hash" ) ) {
QString sha256hash = real_isis_file_info.hash( QCryptographicHash::Sha256 ).toHex();
EXPECT_EQ( jdata["sha256hash"], sha256hash.toStdString() );
n_sha256_compared++;
}
}
}
// Next inventory file
++fileinfo;
}
EXPECT_NE( n_md5_compared, 0);
EXPECT_NE( n_sha1_compared, 0);
EXPECT_NE( n_sha256_compared, 0);
}
TEST_F( IsisDataInventory, IsisDataEvalBadIsisDataDir ) {
Pvl appLog;
QString bad_isisdata_path = tempDir.path() + "/DirDoesNotExist";
QVector<QString> args = {"isisdata=" + bad_isisdata_path,
"datadir=" + bad_isisdata_path };
UserInterface options(APP_XML, args);
// TEST: Bad ISISDATA directory
try {
isisdataeval(options, &appLog);
FAIL() << "Fails when ISISDATA/DATADIR do not exist!" <<std::endl;
}
catch (IException &e ) {
EXPECT_THAT(e.what(), testing::HasSubstr(" is not a directory!"));
}
catch ( ... ) {
FAIL() << "Expected error: ... isisdata directory not found!";
}
}
\ No newline at end of file
#include "IsisDataFixtures.h"
#include <iostream>
#include <fstream>
#include <Qt>
#include <QDateTime>
#include <QStringList>
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include <QFileInfo>
namespace Isis {
QString IsisDataInventory::system_isisdata() const {
return ( m_system_isisdata.expanded() );
}
QString IsisDataInventory::isisdatadir() const {
return ( m_isisdatadir.expanded() );
}
QString IsisDataInventory::isisdata_path() const {
QFileInfo isisdir( isisdatadir() );
return ( isisdir.absoluteFilePath() );
}
size_t IsisDataInventory::size() const {
return ( inventory().size() );
}
QString IsisDataInventory::scrub_path_prefix( const QString &fname,
const QString &path_prefix )
const {
QString t_dbfile = fname;
t_dbfile.replace( isisdatadir(), path_prefix );
return ( t_dbfile );
}
json_t IsisDataInventory::get_real_file_info( const QString &fname ) const {
FileName v_fname = FileName( fname );
QFileInfo qinfo( fname );
json_t file_json;
try {
std::ifstream inputstream ( v_fname.expanded().toStdString() );
file_json = json_t::parse ( inputstream );
}
catch ( ... ) {
file_json["source"] = fname.toStdString();
file_json["filesize"] = qinfo.size();
file_json["exists"] = v_fname.fileExists();
if ( v_fname.fileExists() ) {
file_json["createtime"] = qinfo.birthTime().toString( Qt::ISODateWithMs ).toStdString();
file_json["modifiedtime"] = qinfo.lastModified().toString( Qt::ISODateWithMs ).toStdString();
}
}
return ( file_json );
}
void IsisDataInventory::SetUp() {
TempTestingFiles::SetUp();
m_system_isisdata = FileName( "$ISISDATA" ).expanded();
m_isisdatadir = FileName( "data/isisdata/mockup" );
m_isisdata_inventory.clear();
QDirIterator ddir( isisdatadir(),
QDir::NoDotAndDotDot | QDir::Dirs | QDir::AllDirs | QDir::Files | QDir::System,
QDirIterator::Subdirectories | QDirIterator::FollowSymlinks );
while ( ddir.hasNext() ) {
// Collect the data
QString ddfile = ddir.next();
QString v_name = scrub_path_prefix( ddfile );
QFileInfo f_ddfile = ddir.fileInfo();
if ( !f_ddfile.isDir() ) {
json_t j_data = get_real_file_info( f_ddfile.absoluteFilePath() );
// Add to inventory
m_isisdata_inventory.insert( v_name, IsisDataInventoryFile( v_name, f_ddfile, j_data ) );
}
else {
QDir dirinfo( ddfile );
json_t j_data;
j_data["source"] = v_name.toStdString();
j_data["files"] = dirinfo.count();
// Add to directory inventory
m_isisdata_directories.insert( v_name, IsisDataInventoryFile( v_name, f_ddfile, j_data ) );
}
}
}
void IsisDataInventory::TearDown() {
m_system_isisdata = m_isisdatadir = FileName();
m_isisdata_inventory.clear();
m_isisdata_directories.clear();
}
}
\ No newline at end of file
#ifndef IsisDataFixtures_h
#define IsisDataFixtures_h
#include <map>
#include <string>
#include <QString>
#include <QMap>
#include "FileName.h"
#include "TempFixtures.h"
#include <nlohmann/json.hpp>
using json_t = nlohmann::ordered_json;
namespace Isis {
/**
* @brief Provides a simulated ISISDATA directory tree
*
*/
class IsisDataInventory : public TempTestingFiles {
private:
class IsisDataInventoryFile {
public:
IsisDataInventoryFile( const QString &fname, const QFileInfo &finfo,
const json_t &jsondata = json_t::object() ) {
m_filename = fname;
m_fileinfo = finfo;
m_jsondata = jsondata;
}
~IsisDataInventoryFile( ) { }
inline const QString &name() const {
return ( m_filename );
}
inline const QFileInfo &info() const {
return ( m_fileinfo );
}
inline const json_t &data() const {
return ( m_jsondata );
}
inline bool contains( const QString &key ) const {
return ( m_jsondata.contains( key.toStdString() ) );
}
inline size_t size() const {
return ( info().size() );
}
inline bool compare( const IsisDataInventoryFile &q1,
const IsisDataInventoryFile &q2 ) const {
return ( q1.m_filename < q2.m_filename );
}
protected:
QString m_filename;
QFileInfo m_fileinfo;
json_t m_jsondata;
};
protected:
typedef QMap<QString, IsisDataInventoryFile> IsisDataInventoryMap;
typedef QMap<QString, IsisDataInventoryFile> IsisDataDirectoryMap;
QString system_isisdata() const;
QString isisdatadir() const;
QString isisdata_path() const;
inline const IsisDataInventoryMap &inventory() const {
return ( m_isisdata_inventory );
}
inline const IsisDataDirectoryMap &directories() const {
return ( m_isisdata_directories );
}
size_t size() const;
QString scrub_path_prefix( const QString &fname,
const QString &path_prefix = ".") const;
void SetUp() override;
void TearDown() override;
private:
// Data from ISISDATA simulated file setup
FileName m_system_isisdata;
FileName m_isisdatadir;
IsisDataInventoryMap m_isisdata_inventory;
IsisDataDirectoryMap m_isisdata_directories;
json_t get_real_file_info( const QString &fname ) const;
};
} // namespace Isis
#endif
\ No newline at end of file
hayabusa/kernels/spk/hayabusa_20051116_20051118_v01.bsp
hayabusa/kernels/spk/hayabusa_20051114_20051116_v01.bsp
hayabusa/kernels/spk/amica_kernels.0001.db
hayabusa/kernels/spk/kernels.0002.db
hayabusa/kernels/spk/hayabusa_20051109_20051109_v01.bsp
hayabusa/kernels/spk/itokawa_1989-2010.bsp
hayabusa/kernels/spk/hayabusa_20051115_20051117_v01.bsp
hayabusa/kernels/spk/hayabusa_20051108_20051109_v01.bsp
hayabusa/kernels/spk/hayabusa_20051117_20051119_v01.bsp
hayabusa/kernels/spk/hay_osbj_050911_051118_v1n.bsp
hayabusa/kernels/spk/hayabusa_itokawarendezvous_v01.bsp
hayabusa/kernels/spk/hay_jaxa_050916_051119_v1n.bsp
hayabusa/kernels/spk/kernels.0001.conf
hayabusa/kernels/spk/hayabusa_20051111_20051112_v01.bsp
hayabusa/kernels/spk/hayabusa_20051112_20051114_v01.bsp
hayabusa/kernels/spk/kernels.0001.db
hayabusa/kernels/spk/hayabusa_20051110_20051112_v01.bsp
hayabusa/kernels/fk/itokawa_fixed.tf
hayabusa/kernels/fk/hayabusa_hp.tf
hayabusa/kernels/fk/kernels.0001.db
hayabusa/kernels/lsk/kernels.0001.db
hayabusa/kernels/lsk/naif0009.tls
hayabusa/kernels/sclk/hayabusa.tsc
hayabusa/kernels/sclk/kernels.0001.db
hayabusa/kernels/iak/amicaAddendum002.ti
hayabusa/kernels/iak/kernels.0002.db
hayabusa/kernels/iak/nirsAddendum001.ti
hayabusa/kernels/iak/nirsAddendum002.ti
hayabusa/kernels/iak/kernels.0001.db
hayabusa/kernels/iak/amicaAddendum001.ti
hayabusa/kernels/pck/itokawa_gaskell.tpc
hayabusa/kernels/pck/pck00008.tpc
hayabusa/kernels/pck/kernels.0001.db
hayabusa/kernels/pck/itokawa_aizu504.tpc
hayabusa/kernels/pck/itokawa_gaskell_n3.tpc
hayabusa/kernels/tspk/kernels.0002.db
hayabusa/kernels/tspk/sb_25143_140.bsp
hayabusa/kernels/tspk/de403s.bsp
hayabusa/kernels/tspk/kernels.0001.db
hayabusa/kernels/ik/kernels.0002.db
hayabusa/kernels/ik/xrs10.ti
hayabusa/kernels/ik/amica31.ti
hayabusa/kernels/ik/nirs10.ti
hayabusa/kernels/ik/kernels.0001.db
hayabusa/kernels/ik/lidar10.ti
hayabusa/kernels/ck/hayabusa_itokawarendezvous_v01.bc
hayabusa/kernels/ck/kernels.0001.db
hayabusa/kernels/ck/hayabusa_itokawarendezvous_v02n.bc
hayabusa/kernels/dsk/hay_a_amica_5_itokawashape_v1_0_512q.bds
hayabusa/calibration/flatfield/flat_p.cub
hayabusa/calibration/flatfield/flat_v.cub
hayabusa/calibration/flatfield/flat_ul.cub
hayabusa/calibration/amica/amicaCalibration0006.trn
voyager1/kernels/spk/vgr1_jup230.bsp
voyager1/kernels/spk/kernels.0002.db
voyager1/kernels/spk/voyager_2.ST+1992_m05208u.merged.bsp
voyager1/kernels/spk/vgr1_sat337.bsp
voyager1/kernels/spk/voyager_1.ST+1991_a54418u.merged.bsp
voyager1/kernels/spk/vgr1_sat336.bsp
voyager1/kernels/spk/vg1_sat.bsp
voyager1/kernels/spk/vg1_jup.bsp
voyager1/kernels/spk/kernels.0001.db
voyager1/kernels/aareadme.txt
voyager1/kernels/fk/vg1_v02.tf
voyager1/kernels/fk/kernels.0001.db
voyager1/kernels/fk/vg2_v02.tf
voyager1/kernels/lsk/aareadme.txt
voyager1/kernels/sclk/vg100008.tsc
voyager1/kernels/sclk/vg100043.tsc
voyager1/kernels/sclk/vg100010.tsc
voyager1/kernels/sclk/kernels.0001.db
voyager1/kernels/iak/voyagerAddendum004.ti
voyager1/kernels/iak/voyagerAddendum003.ti
voyager1/kernels/iak/kernels.0001.db
voyager1/kernels/pck/aareadme.txt
voyager1/kernels/pck/pck00010_msgr_v23_europa2020.tpc
voyager1/kernels/pck/kernels.0001.db
voyager1/kernels/ik/vg2_issna_v02.ti
voyager1/kernels/ik/vg2_isswa_v01.ti
voyager1/kernels/ik/kernels.0001.db
voyager1/kernels/ik/vg1_isswa_v01.ti
voyager1/kernels/ik/vg1_issna_v02.ti
voyager1/kernels/ck/vg1_sat_qmw_wa_fc-31100_t2.bc
voyager1/kernels/ck/vg1_jup_qmw_na_fc-31100_t2.bc
voyager1/kernels/ck/kernels.0002.db
voyager1/kernels/ck/kernels_europa.0002.db
voyager1/kernels/ck/vgr1_super_v2.bc
voyager1/kernels/ck/vg1_jup_qmw_wa_fc-31100.bc
voyager1/kernels/ck/makedb
voyager1/kernels/ck/vg1_jup_qmw_wa_fc-31100_t2.bc
voyager1/kernels/ck/vg1_eur_usgs2020.bc
voyager1/kernels/ck/kernels_europa.0001.db
voyager1/kernels/ck/vg1_sat_qmw_na_fc-31100_t2.bc
voyager1/kernels/ck/kernels.0001.db
voyager1/calibration/WA1ORG.CAL.cub
voyager1/calibration/WA1OFF.CAL.cub
voyager1/calibration/voylin.pvl
voyager1/calibration/WA1CLR.CAL.cub
voyager1/calibration/voycal.pvl
voyager1/calibration/WA1BLU.CAL.cub
voyager1/calibration/voylin.pvl.0001
voyager1/calibration/WA1VIO.CAL.cub
voyager1/calibration/WA1GRN.CAL.cub
base/dems/kernels.0007.db
base/dems/ldem_128ppd_Mar2011_clon180_radius_pad.cub
base/dems/kernels.0006.db
base/dems/vesta_hst_dem_0001.cub
base/dems/molaMarsPlanetaryRadius0005.cub
base/dems/DEIMOS_K005_THO_V01.bds
base/dems/Ceres_Dawn_FC_HAMO_DTM_DLR_Global_60ppd_Oct2016_prep.cub
base/dems/Vesta_Dawn_HAMO_DTM_DLR_Global_48ppd.cub
base/dems/MSGR_DEM_USG_EQ_I_V02_prep.cub
base/dems/kernels.0005.db
base/kernels/spk/de118.bsp
base/kernels/spk/jup310.bsp
base/kernels/spk/de245.bsp
base/kernels/spk/kernels.0006.db
base/kernels/spk/aareadme.txt
base/kernels/spk/ura112.bsp
base/kernels/spk/ura111.bsp
base/kernels/spk/de430.bsp
base/kernels/spk/ura115.bsp
base/kernels/spk/mar080.bsp
base/kernels/spk/sat393.bsp
base/kernels/spk/mar097.bsp
base/kernels/spk/de405.bsp
base/kernels/spk/sat425.bsp
base/kernels/spk/nep081.bsp
base/kernels/spk/kernels.0005.db
base/kernels/spk/nep086.bsp
base/kernels/spk/nep090.bsp
base/kernels/fk/moon_assoc_pa.tf
base/kernels/fk/lunarMeanEarth001.tf
base/kernels/fk/moon_071218.tf
base/kernels/fk/lunar_060616.tf
base/kernels/lsk/naif0011.tls
base/kernels/lsk/naif0012.tls
base/kernels/lsk/kernels.0001.db
base/kernels/pck/kernels.0003.db
base/kernels/pck/kernels.0002.db
base/kernels/pck/moon_pa_de418_1950-2050.bpc
base/kernels/pck/pck00008.tpc
base/kernels/pck/lunar_de403_1950-2199_pa.bpc
base/kernels/pck/pck00009.tpc
base/kernels/pck/pck00010_msgr_v23.tpc
smart1/kernels/spk/SMART1_STRUCT_V01.BSP
smart1/kernels/spk/ORMS__041111020517_00206.BSP
smart1/kernels/spk/makedb
smart1/kernels/spk/kernels.0001.db
smart1/kernels/spk/ORMS_______________00233.BSP
smart1/kernels/aareadme.txt
smart1/kernels/fk/SMART1_V1.TF
smart1/kernels/fk/SMART1_V12.TF
smart1/kernels/fk/kernels.0001.db
smart1/kernels/lsk/NAIF0010.TLS
smart1/kernels/lsk/aareadme.txt
smart1/kernels/lsk/NAIF0012.TLS
smart1/kernels/sclk/aareadme.txt
smart1/kernels/sclk/SMART1_070227_STEP.TSC
smart1/kernels/sclk/kernels.0001.db
smart1/kernels/iak/kernels.0001.db
smart1/kernels/pck/PCK00010.TPC
smart1/kernels/pck/PCK00008.TPC
smart1/kernels/pck/kernels.0001.db
smart1/kernels/ik/aareadme.txt
smart1/kernels/ik/SMART1_DCIXS_V03.TI
smart1/kernels/ik/SMART1_AMIE_V01.TI
smart1/kernels/ik/SMART1_SIR_V02.TI
smart1/kernels/ik/kernels.0001.db
smart1/kernels/ik/SMART1_SPEDE_V02.TI
smart1/kernels/ik/SMART1_XSM_V02.TI
smart1/kernels/ck/ATNS_P030929010023_00188.BC
smart1/kernels/ck/makedb
smart1/kernels/ck/ATNS_P060301004212_00233.BC
smart1/kernels/ck/ATNS_P050930150947_00220.BC
smart1/kernels/ck/kernels.0001.db
#!/bin/sh
# Create the test data area for isisdata
# cd ISIS3/isis/test/isisdata
mkdir -p mockup mockprocessing
# Produce the mockup data. Its assumed isisdata_mockup.py is in a runtime path.
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/base --outpath mockprocessing/isisdatamockup/base --ghostdir '$ISISDATA/base'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/hayabusa --outpath mockprocessing/isisdatamockup/hayabusa --ghostdir '$ISISDATA/hayabusa'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/smart1 --outpath mockprocessing/isisdatamockup/smart1 --ghostdir '$ISISDATA/smart1'
isisdata_mockup.py --saveconfig --isisdata $ISISDATA/voyager1 --outpath mockprocessing/isisdatamockup/voyager1 --ghostdir '$ISISDATA/voyager1'
# Copy/install the desired files for the test
rsync -av --files-from=isisdataeval_isisdata_mockup_files.lis mockprocessing/isisdatamockup/ mockup/
/bin/rm -rf mockprocessing
# Run an inventory test for the mockup
isisdataeval isisdata=mockup datadir=mockup toinventory=isisdata_mockup_inventory.csv toissues=isisdata_mockup_issues.csv toerrors=isisdata_mockup_errors.csv hash=md5
{
"source": "$ISISDATA/base/dems/Ceres_Dawn_FC_HAMO_DTM_DLR_Global_60ppd_Oct2016_prep.cub",
"filesize": 467404363,
"createtime": "2022-08-12T22:10:44.000000",
"modifiedtime": "2022-11-24T12:20:56.522490",
"md5hash": "e8e8763630d938caf9cfc52b2820f35b",
"sha256hash": "b0433aa9b460bda0a2ce7802acf8895ab6216d525095c9e9dc2ad7fe67a07f75",
"sha1hash": "1b4d8c0dcf1054470ff00e32598b93b546ace79f"
}
\ No newline at end of file
{
"source": "$ISISDATA/base/dems/DEIMOS_K005_THO_V01.bds",
"filesize": 395264,
"createtime": "2022-09-19T06:12:00.000000",
"modifiedtime": "2022-11-24T12:18:04.936926",
"md5hash": "8e284a502773766527674c3ec78e86d1",
"sha256hash": "dbb21955995e91624df355559580309e4038059850bba23c7feada062f3f6371",
"sha1hash": "4477caca7e6c79c86aa76b686d2325381d941e7c"
}
\ No newline at end of file
{
"source": "$ISISDATA/base/dems/MSGR_DEM_USG_EQ_I_V02_prep.cub",
"filesize": 531052027,
"createtime": "2022-08-12T22:10:56.000000",
"modifiedtime": "2022-11-24T12:20:59.444382",
"md5hash": "4e9239e4d394e01cf15024bece226879",
"sha256hash": "5acbf0f80cba98c3361ec2df28c5cc3037e61a78cb015de2a941ea4504b5e986",
"sha1hash": "6b00ed9be186c89116912aeae4719872a1e140ed"
}
\ No newline at end of file
{
"source": "$ISISDATA/base/dems/Vesta_Dawn_HAMO_DTM_DLR_Global_48ppd.cub",
"filesize": 601826360,
"createtime": "2022-08-12T22:11:00.000000",
"modifiedtime": "2022-11-24T12:21:21.742130",
"md5hash": "a488e544c685ae511ea0ed355a30fdbc",
"sha256hash": "93fec79380f101b6a5b9378b4e1b86ee452abf58ba849abfdae1cb040d8ed929",
"sha1hash": "ba8bb28f414909c12c1c910a562c16b0af92ac5f"
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment