001/*
002 * The contents of this file are subject to the license and copyright detailed
003 * in the LICENSE and NOTICE files at the root of the source tree.
004 */
005package org.duraspace.bagit;
006
007import java.io.IOException;
008import java.nio.file.Paths;
009import java.util.Collections;
010import java.util.HashMap;
011import java.util.HashSet;
012import java.util.LinkedHashMap;
013import java.util.Map;
014import java.util.Set;
015
016import gov.loc.repository.bagit.domain.Manifest;
017import gov.loc.repository.bagit.hash.StandardSupportedAlgorithms;
018import org.junit.Assert;
019import org.junit.Before;
020import org.junit.Test;
021
022/**
023 * Tests for profile validation.
024 *
025 * @author dbernstein
026 * @since Dec 14, 2016
027 */
028public class ProfileValidationUtilTest {
029
030    private static final String FIELD1 = "field1";
031
032    private static final String FIELD2 = "field2";
033
034    private Map<String, ProfileFieldRule> rules;
035
036    private LinkedHashMap<String, String> fields;
037
038    private static final boolean required = true;
039    private static final boolean repeatable = true;
040    private static final boolean recommended = false;
041
042    @Before
043    public void setup() {
044        rules = new HashMap<>();
045        fields = new LinkedHashMap<>();
046        final Set<String> set = new HashSet<>();
047        set.add("value1");
048        set.add("value2");
049        set.add("value3");
050        final ProfileFieldRule field = new ProfileFieldRule(required, repeatable, recommended, "", set);
051        rules.put(FIELD1, field);
052    }
053
054    @Test
055    public void testEnforceValues() throws ProfileValidationException {
056        fields.put(FIELD1, "value1");
057        ProfileValidationUtil.validate("profile-section", rules, fields);
058    }
059
060    @Test(expected = ProfileValidationException.class)
061    public void testEnforceValuesMissingRequired() throws ProfileValidationException {
062        fields.put("field2", "value1");
063        ProfileValidationUtil.validate("profile-section", rules, fields);
064    }
065
066    @Test(expected = ProfileValidationException.class)
067    public void testEnforceValuesInvalidValue() throws ProfileValidationException {
068        fields.put(FIELD1, "invalidValue");
069        ProfileValidationUtil.validate("profile-section", rules, fields);
070    }
071
072    @Test
073    public void testMultipleValidationErrorsInOneExceptionMessage() {
074        fields.put(FIELD1, "invalidValue");
075        rules.put(FIELD2, new ProfileFieldRule(required, repeatable, recommended,
076                                               "field 2 should fail", Collections.emptySet()));
077        fields.put("field3", "any value");
078        try {
079            ProfileValidationUtil.validate("profile-section", rules, fields);
080            Assert.fail("previous line should have failed.");
081        } catch (Exception e) {
082            Assert.assertTrue(e.getMessage().contains(FIELD1));
083            Assert.assertTrue(e.getMessage().contains(FIELD2));
084            Assert.assertFalse(e.getMessage().contains("field3"));
085        }
086    }
087
088    @Test
089    public void testIgnoreSystemGeneratedFields() throws Exception {
090        fields.put(FIELD1, "value1");
091
092        for (String fieldName : ProfileValidationUtil.SYSTEM_GENERATED_FIELD_NAMES) {
093            rules.put(fieldName, null);
094        }
095
096        ProfileValidationUtil.validate("profile-section", rules, fields);
097
098    }
099
100    @Test
101    public void testOnDiskInfoValidation() throws ProfileValidationException, IOException {
102        rules.clear();
103        rules.put("Source-Organization",
104                  new ProfileFieldRule(required, repeatable, recommended, "", Collections.emptySet()));
105        final String bagInfoPath = "src/test/resources/sample/bag/bag-info.txt";
106        ProfileValidationUtil.validate("profile-section", rules, Paths.get(bagInfoPath));
107    }
108
109    @Test
110    public void testGlobalTagMatch() throws ProfileValidationException {
111        final Set<String> allowedTags = Collections.singleton("**");
112        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
113        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info/test-info.txt"), allowedTags);
114    }
115
116    @Test
117    public void testEmptyListValidates() throws ProfileValidationException {
118        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), Collections.emptySet());
119    }
120
121    @Test
122    public void testUniqueTagMatch() throws ProfileValidationException {
123        final Set<String> allowedTags = Collections.singleton("test-info.txt");
124        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
125    }
126
127    @Test(expected = ProfileValidationException.class)
128    public void testTagIsNotAllowed() throws ProfileValidationException {
129        final Set<String> allowedTags = Collections.singleton("test-tag.txt");
130        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
131    }
132
133    @Test
134    public void testSubDirectoryMatch() throws ProfileValidationException {
135        final Set<String> allowedTags = Collections.singleton("ddp-tags/test-*");
136        ProfileValidationUtil.validateTagIsAllowed(Paths.get("ddp-tags/test-info.txt"), allowedTags);
137        ProfileValidationUtil.validateTagIsAllowed(Paths.get("ddp-tags/test-extra-info.txt"), allowedTags);
138    }
139
140    @Test
141    public void testTagValidateIgnoresRequired() throws ProfileValidationException {
142        final Set<String> allowedTags = Collections.singleton("test-info.txt");
143        ProfileValidationUtil.validateTagIsAllowed(Paths.get("bag-info.txt"), allowedTags);
144        ProfileValidationUtil.validateTagIsAllowed(Paths.get("bagit.txt"), allowedTags);
145        ProfileValidationUtil.validateTagIsAllowed(Paths.get("manifest-md5.txt"), allowedTags);
146        ProfileValidationUtil.validateTagIsAllowed(Paths.get("tagmanifest-sha512.txt"), allowedTags);
147    }
148
149    @Test
150    public void testVerifyManifests() {
151        final String type = "TEST";
152        final Manifest manifest = new Manifest(StandardSupportedAlgorithms.SHA1);
153        final Set<Manifest> manifests = Collections.singleton(manifest);
154        final Set<String> constraints = Collections.singleton("sha1");
155
156        // check that no errors were returned
157        Assert.assertTrue(ProfileValidationUtil.validateManifest(manifests, constraints, constraints, type).isEmpty());
158        Assert.assertTrue(
159            ProfileValidationUtil.validateManifest(manifests, constraints, Collections.emptySet(), type).isEmpty());
160    }
161
162    @Test
163    public void testVerifyManifestFailure() {
164        final String type = "TEST";
165        final Manifest manifest = new Manifest(StandardSupportedAlgorithms.SHA1);
166        final Set<Manifest> manifests = Collections.singleton(manifest);
167        final Set<String> required = Collections.singleton("md5");
168        final Set<String> allowed = Collections.singleton("md5");
169
170        final String result = ProfileValidationUtil.validateManifest(manifests, required, allowed, type);
171        Assert.assertTrue(result.contains("Missing"));
172        Assert.assertTrue(result.contains("Unsupported"));
173    }
174
175}