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.singleton("bagit-support")));
105        rules.put("Organization-Address",
106                  new ProfileFieldRule(required, repeatable, recommended, "",
107                                       Collections.singleton("localhost-dot-localdomain")));
108        final String bagInfoPath = "src/test/resources/sample/bag/bag-info.txt";
109        ProfileValidationUtil.validate("profile-section", rules, Paths.get(bagInfoPath));
110    }
111
112    @Test
113    public void testGlobalTagMatch() throws ProfileValidationException {
114        final Set<String> allowedTags = Collections.singleton("**");
115        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
116        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info/test-info.txt"), allowedTags);
117    }
118
119    @Test
120    public void testEmptyListValidates() throws ProfileValidationException {
121        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), Collections.emptySet());
122    }
123
124    @Test
125    public void testUniqueTagMatch() throws ProfileValidationException {
126        final Set<String> allowedTags = Collections.singleton("test-info.txt");
127        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
128    }
129
130    @Test(expected = ProfileValidationException.class)
131    public void testTagIsNotAllowed() throws ProfileValidationException {
132        final Set<String> allowedTags = Collections.singleton("test-tag.txt");
133        ProfileValidationUtil.validateTagIsAllowed(Paths.get("test-info.txt"), allowedTags);
134    }
135
136    @Test
137    public void testSubDirectoryMatch() throws ProfileValidationException {
138        final Set<String> allowedTags = Collections.singleton("ddp-tags/test-*");
139        ProfileValidationUtil.validateTagIsAllowed(Paths.get("ddp-tags/test-info.txt"), allowedTags);
140        ProfileValidationUtil.validateTagIsAllowed(Paths.get("ddp-tags/test-extra-info.txt"), allowedTags);
141    }
142
143    @Test
144    public void testTagValidateIgnoresRequired() throws ProfileValidationException {
145        final Set<String> allowedTags = Collections.singleton("test-info.txt");
146        ProfileValidationUtil.validateTagIsAllowed(Paths.get("bag-info.txt"), allowedTags);
147        ProfileValidationUtil.validateTagIsAllowed(Paths.get("bagit.txt"), allowedTags);
148        ProfileValidationUtil.validateTagIsAllowed(Paths.get("manifest-md5.txt"), allowedTags);
149        ProfileValidationUtil.validateTagIsAllowed(Paths.get("tagmanifest-sha512.txt"), allowedTags);
150    }
151
152    @Test
153    public void testVerifyManifests() {
154        final String type = "TEST";
155        final Manifest manifest = new Manifest(StandardSupportedAlgorithms.SHA1);
156        final Set<Manifest> manifests = Collections.singleton(manifest);
157        final Set<String> constraints = Collections.singleton("sha1");
158
159        // check that no errors were returned
160        Assert.assertTrue(ProfileValidationUtil.validateManifest(manifests, constraints, constraints, type).isEmpty());
161        Assert.assertTrue(
162            ProfileValidationUtil.validateManifest(manifests, constraints, Collections.emptySet(), type).isEmpty());
163    }
164
165    @Test
166    public void testVerifyManifestFailure() {
167        final String type = "TEST";
168        final Manifest manifest = new Manifest(StandardSupportedAlgorithms.SHA1);
169        final Set<Manifest> manifests = Collections.singleton(manifest);
170        final Set<String> required = Collections.singleton("md5");
171        final Set<String> allowed = Collections.singleton("md5");
172
173        final String result = ProfileValidationUtil.validateManifest(manifests, required, allowed, type);
174        Assert.assertTrue(result.contains("Missing"));
175        Assert.assertTrue(result.contains("Unsupported"));
176    }
177
178}