1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
|
package blackout;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import unsw.blackout.BlackoutController;
import unsw.blackout.FileTransferException;
import unsw.utils.Angle;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static unsw.utils.MathsHelper.RADIUS_OF_JUPITER;
@TestInstance(value = Lifecycle.PER_CLASS)
public class Task2Tests {
@Test
public void testDownloadSpeed() {
BlackoutController controller = new BlackoutController();
// The expected download speed should be (download speed / num transferring files), with the remainder ignored.
controller.createSatellite("Satellite1", "ShrinkingSatellite", 1000 + RADIUS_OF_JUPITER, Angle.fromDegrees(320));
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(310));
controller.createDevice("DeviceB", "LaptopDevice", Angle.fromDegrees(310));
String contents = "a relatively long string";
controller.addFileToDevice("DeviceA", "file1", contents);
controller.addFileToDevice("DeviceB", "file2", contents);
assertDoesNotThrow(() -> controller.sendFile("file1", "DeviceA", "Satellite1"));
assertDoesNotThrow(() -> controller.sendFile("file2", "DeviceB", "Satellite1"));
// shrinking satellite is 15 bytes per tick, so should be 15/2 = 7.
controller.simulate();
assertEquals(7, controller.getInfo("Satellite1").getFiles().get("file1").getData().length());
assertEquals(7, controller.getInfo("Satellite1").getFiles().get("file2").getData().length());
// again, should be 14
controller.simulate();
assertEquals(14, controller.getInfo("Satellite1").getFiles().get("file1").getData().length());
assertEquals(14, controller.getInfo("Satellite1").getFiles().get("file2").getData().length());
}
@Test
public void testDeleteFiles() {
BlackoutController controller = new BlackoutController();
// Files that are being transferred should be deleted if they are in transmission, and kept if they are not.
controller.createSatellite("Satellite1", "StandardSatellite", 1000 + RADIUS_OF_JUPITER, Angle.fromDegrees(310));
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(310));
// Upload a file to the satellite, should be there after 1 tick.
controller.addFileToDevice("DeviceA", "file1", "1");
assertDoesNotThrow(() -> controller.sendFile("file1", "DeviceA", "Satellite1"));
controller.simulate();
assert(controller.getInfo("Satellite1").getFiles().size() == 1);
// Upload another file, which will not transmit in time.
controller.addFileToDevice("DeviceA", "file2", "this string will take a fair amount of ticks to transmit");
assertDoesNotThrow(() -> controller.sendFile("file2", "DeviceA", "Satellite1"));
controller.simulate();
assert(controller.getInfo("Satellite1").getFiles().size() == 2);
for (int i = 0; i < 50; ++i) {
controller.simulate();
}
// At this point we should be occluded and out of range,
// while the file was in transmission - zero files should be present.
assert(controller.getInfo("Satellite1").getFiles().size() == 1);
}
@Test
public void testTransientDeleteFile() {
BlackoutController controller = new BlackoutController();
// Files should NOT be deleted after occlusion or running out of distance.
controller.createSatellite("Satellite1", "ElephantSatellite", 1000 + RADIUS_OF_JUPITER, Angle.fromDegrees(330));
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(310));
// Upload a file which will not transmit in time.
controller.addFileToDevice("DeviceA", "file1", "this string will take a fair amount of ticks to transmit but just to be sure");
assertDoesNotThrow(() -> controller.sendFile("file1", "DeviceA", "Satellite1"));
controller.simulate();
assert(controller.getInfo("Satellite1").getFiles().size() == 1);
assert(controller.getInfo("Satellite1").getFiles().get("file1").hasTransferCompleted() == false);
// The file should NOT be deleted after this period.
// In addition the file should have transferred fully by this time.
for (int i = 0; i < 180; ++i) {
controller.simulate();
}
assert(controller.getInfo("Satellite1").getFiles().size() == 1);
assert(controller.getInfo("Satellite1").getFiles().get("file1").hasTransferCompleted() == true);
}
@Test
public void testRelayAccess() {
BlackoutController controller = new BlackoutController();
// We create two devices on one side of the planet, they should not be able to communicate.
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(180));
controller.createDevice("DeviceB", "LaptopDevice", Angle.fromDegrees(0));
assert(controller.communicableEntitiesInRange("DeviceA").size() == 0);
assert(controller.communicableEntitiesInRange("DeviceB").size() == 0);
// We create a chain of relays that should connect the two devices.
int OFFSET = 15_000;
int NUM_SATELLITES = 5;
for (int i = 0; i < NUM_SATELLITES; ++i) {
controller.createSatellite("Satellite" + i, "RelaySatellite", OFFSET + RADIUS_OF_JUPITER, Angle.fromDegrees(180 - i * (180 / NUM_SATELLITES)));
}
// We should be able to communicate with all relays, plus the other device.
assert(controller.communicableEntitiesInRange("DeviceA").size() == NUM_SATELLITES + 1);
assert(controller.communicableEntitiesInRange("DeviceB").size() == NUM_SATELLITES + 1);
}
@Test
public void testCloudStorageDevice() {
BlackoutController controller = new BlackoutController();
// The size of the string in cloudstoragedevice should be the same in the satellite
// but larger after transfer into the laptop device. (Files are only decompressed
// inside devices (minus cloudstoragedevice).
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(180));
controller.createDevice("DeviceB", "CloudStorageDevice", Angle.fromDegrees(180));
controller.createSatellite("Satellite1", "ShrinkingSatellite", 10000 + RADIUS_OF_JUPITER, Angle.fromDegrees(180));
// Compression isn't guaranteed, but if we repeat digits we can improve our chances.
// Send the file to the satellite, it should be the same size as in the cloudstoragedevice.
controller.addFileToDevice("DeviceB", "file", "biiiiiiiiiiiiiiiiiiiiiiiig");
assertDoesNotThrow(() -> controller.sendFile("file", "DeviceB", "Satellite1"));
controller.simulate(); // should arrive in two ticks
controller.simulate();
assert(controller.getInfo("Satellite1").getFiles().get("file").getFileSize() == controller.getInfo("DeviceB").getFiles().get("file").getFileSize());
assertDoesNotThrow(() -> controller.sendFile("file", "Satellite1", "DeviceA"));
controller.simulate();
// TODO make <
assert(controller.getInfo("Satellite1").getFiles().get("file").getFileSize() <= controller.getInfo("DeviceA").getFiles().get("file").getFileSize());
}
@Test
public void testSendFileExceptions() {
BlackoutController controller = new BlackoutController();
controller.createDevice("DeviceA", "LaptopDevice", Angle.fromDegrees(180));
controller.createDevice("DeviceB", "LaptopDevice", Angle.fromDegrees(180));
controller.createSatellite("Satellite1", "ShrinkingSatellite", 15000 + RADIUS_OF_JUPITER, Angle.fromDegrees(180));
// VirtualFileNotFoundException if the file doesn't exist on fromID
assertThrows(FileTransferException.VirtualFileNotFoundException.class, () -> controller.sendFile("?", "DeviceA", "Satellite1"));
// ... or it's a partial file.
controller.addFileToDevice("DeviceA", "file", "contents");
assertDoesNotThrow(() -> controller.sendFile("file", "DeviceA", "Satellite1"));
assertThrows(FileTransferException.VirtualFileNotFoundException.class, () -> controller.sendFile("file", "Satellite1", "DeviceB"));
controller.simulate(); // make the file arrive
assert(controller.getInfo("Satellite1").getFiles().get("file").hasTransferCompleted());
// VirtualFileAlreadyExistsException if the file already exists on targetId.
assertThrows(FileTransferException.VirtualFileAlreadyExistsException.class, () -> controller.sendFile("file", "Satellite1", "DeviceA"));
// or if it's currently downloading
controller.addFileToDevice("DeviceA", "file1", "contents");
assertDoesNotThrow(() -> controller.sendFile("file1", "DeviceA", "Satellite1"));
controller.simulate();
assert(controller.getInfo("Satellite1").getFiles().get("file1").hasTransferCompleted());
assertDoesNotThrow(() -> controller.sendFile("file1", "Satellite1", "DeviceB"));
assert(controller.getInfo("DeviceB").getFiles().get("file1").hasTransferCompleted() == false);
assertThrows(FileTransferException.VirtualFileAlreadyExistsException.class, () -> controller.sendFile("file1", "Satellite1", "DeviceB"));
controller.simulate(); // send all files
// At this point our satellite has 0 files currently downloading and 2 files stored.
// VirtualFileNoBandwidthException if we are sending too many files.
// 15 bytes / tick = max of 15 files.
assertDoesNotThrow(() -> {
for (int i = 2; i < 15 + 2; ++i) {
controller.addFileToDevice("DeviceA", "file" + i, "contents");
controller.sendFile("file" + i, "DeviceA", "Satellite1");
}
});
controller.addFileToDevice("DeviceA", "too many files file", "contents");
assertThrows(FileTransferException.VirtualFileNoBandwidthException.class, () -> controller.sendFile("too many files file", "DeviceA", "Satellite1"));
// VirtualFileNoStorageSpaceException should throw if the lack of room was due to a max file cap
// max file cap of three for StandardSatellite, we have to be careful to avoid it's bandwidth limits
controller.createSatellite("Satellite2", "StandardSatellite", 15000 + RADIUS_OF_JUPITER, Angle.fromDegrees(180));
assertDoesNotThrow(() -> {
for (int i = 0; i < 3; ++i) {
controller.addFileToDevice("DeviceA", "unique_file" + i, "1");
controller.sendFile("unique_file" + i, "DeviceA", "Satellite2");
controller.simulate();
}
});
controller.addFileToDevice("DeviceA", "unique_file3", "contents");
assertThrows(FileTransferException.VirtualFileNoStorageSpaceException.class, () -> controller.sendFile("unique_file3", "DeviceA", "Satellite2"));
// ... or if we exceed the storage byte limit
controller.createSatellite("Satellite3", "StandardSatellite", 15000 + RADIUS_OF_JUPITER, Angle.fromDegrees(180));
controller.addFileToDevice("DeviceA", "big_file", "a very long string that definitely exceeds the max byte storage amount of satellite3");
assertThrows(FileTransferException.VirtualFileNoStorageSpaceException.class, () -> controller.sendFile("big_file", "DeviceA", "Satellite3"));
}
}
|