• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.google.archivepatcher.generator;
16 
17 import com.google.archivepatcher.shared.JreDeflateParameters;
18 import com.google.archivepatcher.shared.PatchConstants;
19 import com.google.archivepatcher.shared.TypedRange;
20 
21 import org.junit.After;
22 import org.junit.Assert;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.junit.runner.RunWith;
26 import org.junit.runners.JUnit4;
27 
28 import java.io.ByteArrayInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.DataInputStream;
31 import java.io.File;
32 import java.io.FileOutputStream;
33 import java.io.IOException;
34 import java.util.Collections;
35 import java.util.List;
36 
37 /**
38  * Tests for {@link PatchWriter}.
39  */
40 @RunWith(JUnit4.class)
41 @SuppressWarnings("javadoc")
42 public class PatchWriterTest {
43   // This is Integer.MAX_VALUE + 1.
44   private static final long BIG = 2048L * 1024L * 1024L;
45 
46   private static final JreDeflateParameters DEFLATE_PARAMS = JreDeflateParameters.of(6, 0, true);
47 
48   private static final TypedRange<Void> OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE =
49       new TypedRange<Void>(BIG, 17L, null);
50 
51   private static final TypedRange<JreDeflateParameters> NEW_DELTA_FRIENDLY_UNCOMPRESS_RANGE =
52       new TypedRange<JreDeflateParameters>(BIG - 100L, BIG, DEFLATE_PARAMS);
53 
54   private static final TypedRange<JreDeflateParameters> NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE =
55       new TypedRange<JreDeflateParameters>(BIG, BIG, DEFLATE_PARAMS);
56 
57   private static final List<TypedRange<Void>> OLD_DELTA_FRIENDLY_UNCOMPRESS_PLAN =
58       Collections.singletonList(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE);
59 
60   private static final List<TypedRange<JreDeflateParameters>> NEW_DELTA_FRIENDLY_UNCOMPRESS_PLAN =
61       Collections.singletonList(NEW_DELTA_FRIENDLY_UNCOMPRESS_RANGE);
62 
63   private static final List<TypedRange<JreDeflateParameters>> NEW_DELTA_FRIENDLY_RECOMPRESS_PLAN =
64       Collections.singletonList(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE);
65 
66   private static final long DELTA_FRIENDLY_OLD_FILE_SIZE = BIG - 75L;
67 
68   private static final long DELTA_FRIENDLY_NEW_FILE_SIZE = BIG + 75L;
69 
70   private static final PreDiffPlan PLAN =
71       new PreDiffPlan(
72           Collections.<QualifiedRecommendation>emptyList(),
73           OLD_DELTA_FRIENDLY_UNCOMPRESS_PLAN,
74           NEW_DELTA_FRIENDLY_UNCOMPRESS_PLAN,
75           NEW_DELTA_FRIENDLY_RECOMPRESS_PLAN);
76 
77   private static final String DELTA_CONTENT = "this is a really cool delta, woo";
78 
79   private File deltaFile = null;
80 
81   private ByteArrayOutputStream buffer = null;
82 
83   @Before
setup()84   public void setup() throws IOException {
85     buffer = new ByteArrayOutputStream();
86     deltaFile = File.createTempFile("patchwritertest", "delta");
87     deltaFile.deleteOnExit();
88     try (FileOutputStream out = new FileOutputStream(deltaFile)) {
89       out.write(DELTA_CONTENT.getBytes());
90       out.flush();
91     }
92   }
93 
94   @After
tearDown()95   public void tearDown() {
96     deltaFile.delete();
97   }
98 
99   @Test
testWriteV1Patch()100   public void testWriteV1Patch() throws IOException {
101     // ---------------------------------------------------------------------------------------------
102     // CAUTION - DO NOT CHANGE THIS FUNCTION WITHOUT DUE CONSIDERATION FOR BREAKING THE PATCH FORMAT
103     // ---------------------------------------------------------------------------------------------
104     // This test writes a simple patch with all the static data listed above and verifies it.
105     // This code MUST be INDEPENDENT of the real patch parser code, even if it is partially
106     // redundant; this guards against accidental changes to the patch writer that could alter the
107     // format and otherwise escape detection.
108     PatchWriter writer =
109         new PatchWriter(
110             PLAN, DELTA_FRIENDLY_OLD_FILE_SIZE, DELTA_FRIENDLY_NEW_FILE_SIZE, deltaFile);
111     writer.writeV1Patch(buffer);
112     DataInputStream patchIn = new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()));
113     byte[] eightBytes = new byte[8];
114 
115     // Start by reading the signature and flags
116     patchIn.readFully(eightBytes);
117     Assert.assertArrayEquals(PatchConstants.IDENTIFIER.getBytes("US-ASCII"), eightBytes);
118     Assert.assertEquals(0, patchIn.readInt()); // Flags, all reserved in v1
119 
120     Assert.assertEquals(DELTA_FRIENDLY_OLD_FILE_SIZE, patchIn.readLong());
121 
122     // Read the uncompression instructions
123     Assert.assertEquals(1, patchIn.readInt()); // Number of old archive uncompression instructions
124     Assert.assertEquals(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE.getOffset(), patchIn.readLong());
125     Assert.assertEquals(OLD_DELTA_FRIENDLY_UNCOMPRESS_RANGE.getLength(), patchIn.readLong());
126 
127     // Read the recompression instructions
128     Assert.assertEquals(1, patchIn.readInt()); // Number of new archive recompression instructions
129     Assert.assertEquals(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE.getOffset(), patchIn.readLong());
130     Assert.assertEquals(NEW_DELTA_FRIENDLY_RECOMPRESS_RANGE.getLength(), patchIn.readLong());
131     // Now the JreDeflateParameters for the record
132     Assert.assertEquals(
133         PatchConstants.CompatibilityWindowId.DEFAULT_DEFLATE.patchValue, patchIn.read());
134     Assert.assertEquals(DEFLATE_PARAMS.level, patchIn.read());
135     Assert.assertEquals(DEFLATE_PARAMS.strategy, patchIn.read());
136     Assert.assertEquals(DEFLATE_PARAMS.nowrap ? 1 : 0, patchIn.read());
137 
138     // Delta section. V1 patches have exactly one delta entry and it is always mapped to the entire
139     // file contents of the delta-friendly archives
140     Assert.assertEquals(1, patchIn.readInt()); // Number of difference records
141     Assert.assertEquals(PatchConstants.DeltaFormat.BSDIFF.patchValue, patchIn.read());
142     Assert.assertEquals(0, patchIn.readLong()); // Old delta-friendly range start
143     Assert.assertEquals(DELTA_FRIENDLY_OLD_FILE_SIZE, patchIn.readLong()); // old range length
144     Assert.assertEquals(0, patchIn.readLong()); // New delta-friendly range start
145     Assert.assertEquals(DELTA_FRIENDLY_NEW_FILE_SIZE, patchIn.readLong()); // new range length
146     byte[] expectedDeltaContent = DELTA_CONTENT.getBytes("US-ASCII");
147     Assert.assertEquals(expectedDeltaContent.length, patchIn.readLong());
148     byte[] actualDeltaContent = new byte[expectedDeltaContent.length];
149     patchIn.readFully(actualDeltaContent);
150     Assert.assertArrayEquals(expectedDeltaContent, actualDeltaContent);
151   }
152 }
153