Skip to content
Snippets Groups Projects
test_lemi_metadata.py 10.4 KiB
Newer Older
# -*- coding: utf-8 -*-

"""Tests for `lemi_metadata` module."""

import openpyxl
import pickle
import unittest

from obspy import UTCDateTime
from pathlib import Path

from lemi2seed.lemi_data import LemiData
from lemi2seed.lemi_metadata import LemiMetadata
from lemi2seed.logging import setup_logger
from lemi2seed.metadata_category import Elec, Mag, Aux

OUTPUT_MSEED = Path(__file__).resolve().parent.joinpath('MSEED')
OUTPUT_LOG = Path(__file__).resolve().parent.joinpath('LOG')
OUTPUT_XML = Path(__file__).resolve().parent.joinpath('STATIONXML')
TEST_DIR = Path(__file__).resolve().parent.joinpath('test_data')
SCR_DIR = "lemi2seed.lemi_metadata"

# Set up logging
logger = setup_logger(SCR_DIR)


class TestLemiMetadata(unittest.TestCase):
    """Test suite for LemiMetadata class."""

    def setUp(self):
        """Set up test fixtures"""
        lemi_data = LemiData(TEST_DIR.joinpath("EM", "TEST5"), OUTPUT_MSEED, OUTPUT_LOG)
        lemi_data.prep_data()
        self.data = lemi_data
        self.path2md = TEST_DIR.joinpath("METADATA")
        self.path2md_fail_1 = TEST_DIR.joinpath("METADATA_NO_FIELD_SHEET")
        self.path2md_fail_2 = TEST_DIR.joinpath("METADATA_CORRUPTED")
        self.file = self.path2md.joinpath('LEMI_Install_Sheet.xlsx')
        self.md = LemiMetadata(self.path2md, OUTPUT_XML, self.data)
        file_ = self.path2md.joinpath('metadata_fields.pkl')
        with open(file_, 'rb') as fin:
            self.md_fields_no_reformat = pickle.load(fin)
        file_ = self.path2md.joinpath('metadata_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            self.md_fields = pickle.load(fin)

    def test_scan_path2md_field_sheet_provided(self):
        """Test basic functionality of scan_path2md."""
        md = LemiMetadata(self.path2md, OUTPUT_XML, self.data)
        self.assertEqual(*md.filenames, self.file)

    def test_scan_path2md_no_field_sheet_provided(self):
        """Test basic functionality of scan_path2md."""
        with self.assertLogs(logger, level='ERROR') as cmd:
            LemiMetadata(self.path2md_fail_1, OUTPUT_XML, self.data)
        msg = ("No field sheet found under the following path - {}. All "
               "metadata will have to be provided using the GUI!"
               .format(self.path2md_fail_1))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_get_md_field_pass(self):
        """Test basic functionality of get_md_field."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        self.assertEqual(LemiMetadata.get_md_field(sheet, 'B3'), 'EM')
        workbook.close()

    def test_get_md_field_fail(self):
        """Test basic functionality of get_md_field."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        with self.assertLogs(logger, level='ERROR'):
            self.assertIsNone(LemiMetadata.get_md_field(sheet, 12))
        workbook.close()

    def test_identify_field_sheet_pass(self):
        """Test basic functionality of identify_field_sheet."""
        workbook = openpyxl.load_workbook(self.file, data_only=True)
        sheet = workbook.active
        sheet_type = self.md.identify_field_sheet(sheet, 'LEMI_Install_Sheet.xlsx')
        self.assertEqual(sheet_type, 'install_sheet')
        workbook.close()

    def test_identify_field_sheet_fail(self):
        """Test basic functionality of identify_field_sheet."""
        md = LemiMetadata(self.path2md_fail_2, OUTPUT_XML, self.data)
        file_ = self.path2md_fail_2.joinpath('LEMI_Install_Sheet_2.xlsx')
        workbook = openpyxl.load_workbook(file_, data_only=True)
        sheet = workbook.active
        with self.assertLogs(logger, level='WARNING') as cmd:
            md.identify_field_sheet(sheet, file_)
        msg = ("The following file {} does not have the proper header. The "
               "provided spread sheet templates were not used or their "
               "layout was modified. Skipping file!".format(file_))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])
        workbook.close()

    def test_reformat_run(self):
        """Test basic functionality of reformat_run."""
        run_fields = self.md_fields_no_reformat['Run']

        file_ = self.path2md.joinpath('run_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.md.reformat_run(run_fields), reformatted)

    def test_reformat_elec(self):
        """Test basic functionality of reformat_elec."""
        elec_fields = self.md_fields_no_reformat['Elec']
        file_ = self.path2md.joinpath('electric_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.md.reformat_elec(elec_fields), reformatted)

    def test_reformat_mag(self):
        """Test basic functionality of reformat_mag."""
        mag_fields = self.md_fields_no_reformat['Mag']
        file_ = self.path2md.joinpath('magnetic_fields_reformatted.pkl')
        with open(file_, 'rb') as fin:
            reformatted = pickle.load(fin)
        self.assertDictEqual(self.md.reformat_mag(mag_fields), reformatted)

    def test_reformat_md_dict(self):
        """Test basic functionality of reformat_md_dict."""
        self.assertDictEqual(self.md.reformat_md_dict(self.md_fields_no_reformat),
                             self.md_fields)

    def test_from_field_sheets_failed_to_open(self):
        """Test basic functionality of from_field_sheets"""
        self.md.filenames = [self.path2md_fail_2.joinpath('LEMI_Install_Sheet_1.xlsx')]
        with self.assertLogs(logger, level='ERROR') as cmd:
            self.md.from_field_sheets
        msg = ("Failed to open field sheet: {} - Skipping file - Exception: "
               "File is not a zip file".format(self.md.filenames[0]))
        self.assertEqual(cmd.output, [":".join(['ERROR', SCR_DIR, msg])])

    def test_from_field_sheets_duplicate_sheet_type(self):
        """Test basic functionality of from_field_sheets"""
        self.md.filenames = [self.file] * 2
        with self.assertLogs(logger, level='WARNING') as cmd:
            self.md.from_field_sheets
        msg = ("Already parsed the install sheet - You may have more than one "
               "install sheet - Skipping {}!".format(self.file))
        self.assertEqual(cmd.output, [":".join(['WARNING', SCR_DIR, msg])])

    def test_from_field_sheets_expected_workflow(self):
        """Test basic functionality of from_field_sheets"""
        self.assertDictEqual(self.md.from_field_sheets, self.md_fields)

    def test_init_run_md_props(self):
        """Test basic functionality of init_run_md_props."""
        time_period_starts = [UTCDateTime(2020, 9, 30, 21, 5),
                              UTCDateTime(2020, 9, 30, 21, 12),
                              UTCDateTime(2020, 9, 30, 21, 14),
                              UTCDateTime(2020, 10, 1, 0, 0)]
        time_period_ends = [UTCDateTime(2020, 9, 30, 21, 11, 1),
                            UTCDateTime(2020, 9, 30, 21, 13, 45),
                            UTCDateTime(2020, 9, 30, 21, 27, 59),
                            UTCDateTime(2020, 10, 1, 0, 5, 59)]
        self.md.init_run_md_props()
        for ind, run in enumerate(self.md.run):
            self.assertEqual(run.start, time_period_starts[ind])
            self.assertEqual(run.end, time_period_ends[ind])
            self.assertEqual(run.resource_id, 'mt.run.id:' + self.md.run_list[ind])

    def test_init_cha_md_props_elec(self):
        """Test basic functionality of init_cha_md_props."""
        cha = self.md.init_cha_md_props('elec', 'a')
        self.assertIsInstance(cha, Elec)
        self.assertEqual(cha.elev, round(self.md.data_stats['elev'], 3))
        self.assertEqual(cha.lat, round(self.md.data_stats['lat'], 3))
        self.assertEqual(cha.lon, round(self.md.data_stats['lon'], 3))
        self.assertEqual(cha.run_id, 'a')

    def test_init_cha_md_props_mag(self):
        """Test basic functionality of init_cha_md_props."""
        cha = self.md.init_cha_md_props('mag', 'a')
        self.assertIsInstance(cha, Mag)
        self.assertEqual(cha.elev, round(self.md.data_stats['elev'], 3))
        self.assertEqual(cha.lat, round(self.md.data_stats['lat'], 3))
        self.assertEqual(cha.lon, round(self.md.data_stats['lon'], 3))
        self.assertEqual(cha.run_id, 'a')

    def test_init_cha_md_props_aux(self):
        """Test basic functionality of init_cha_md_props."""
        cha = self.md.init_cha_md_props('aux', 'a')
        self.assertIsInstance(cha, Aux)
        self.assertEqual(cha.elev, round(self.md.data_stats['elev'], 3))
        self.assertEqual(cha.lat, round(self.md.data_stats['lat'], 3))
        self.assertEqual(cha.lon, round(self.md.data_stats['lon'], 3))
        self.assertEqual(cha.run_id, 'a')

    def test_dc2dict(self):
        """Test basic functionality of dc2dict."""
        cha = self.md.init_cha_md_props('elec', 'a')
        self.assertDictEqual(self.md.dc2dict(cha),
                             {'elev': 2201.725,
                              'lat': 34.048,
                              'lon': -107.128,
                              'inst_manufacturer': None,
                              'inst_model': None,
                              'inst_specs': None,
                              'inst_type': None,
                              'meas_azimuth': None,
                              'meas_tilt': None,
                              'sample_rate': 1.0,
                              'cha_num': None,
                              'contact_resistance_end': None,
                              'contact_resistance_start': None,
                              'dc_end': None,
                              'dc_start': None,
                              'dipole_len': None,
                              'neg_elec_dir': None,
                              'neg_elec_sn': None,
                              'pos_elec_dir': None,
                              'pos_elec_sn': None})

    def test_for_gui_md_not_populated(self):
        """Test basic functionality of for_gui."""
        file_ = self.path2md.joinpath('gui_metadata_not_populated.pkl')
        with open(file_, 'rb') as fin:
            expected = pickle.load(fin)
        self.assertDictEqual(self.md.for_gui, expected)

    def tearDown(self):
        """Tear down test fixtures"""
        file_ = self.path2md.joinpath('lemi_metadata.pkl')
        if file_.is_file():
            file_.unlink()