Skip to content

Commit 2f39327

Browse files
committed
Adds multiswarm test
1 parent d452293 commit 2f39327

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
using CodexPlugin;
2+
using FileUtils;
3+
using Logging;
4+
using NUnit.Framework;
5+
using Utils;
6+
7+
namespace CodexTests.DownloadConnectivityTests
8+
{
9+
[TestFixture]
10+
public class MultiswarmTests : AutoBootstrapDistTest
11+
{
12+
[Test]
13+
[Combinatorial]
14+
public void Multiswarm(
15+
[Values(3, 5)] int numFiles,
16+
[Values(5, 20)] int fileSizeMb,
17+
[Values(1)] int uploadersPerFile,
18+
[Values(3)] int downloadersPerFile,
19+
[Values(1)] int maxUploadsPerNode,
20+
[Values(2, 3)] int maxDownloadsPerNode
21+
)
22+
{
23+
var plan = CreateThePlan(numFiles, uploadersPerFile, downloadersPerFile, maxUploadsPerNode, maxDownloadsPerNode);
24+
Assert.That(plan.NodePlans.Count, Is.LessThan(30));
25+
26+
RunThePlan(plan, fileSizeMb);
27+
}
28+
29+
private void RunThePlan(Plan plan, int fileSizeMb)
30+
{
31+
foreach (var filePlan in plan.FilePlans) filePlan.File = GenerateTestFile(fileSizeMb.MB());
32+
var nodes = StartCodex(plan.NodePlans.Count);
33+
for (int i = 0; i < plan.NodePlans.Count; i++) plan.NodePlans[i].Node = nodes[i];
34+
35+
// Upload all files to their nodes.
36+
foreach (var filePlan in plan.FilePlans)
37+
{
38+
foreach (var uploader in filePlan.Uploaders)
39+
{
40+
filePlan.Cid = uploader.Node!.UploadFile(filePlan.File!);
41+
}
42+
}
43+
44+
Thread.Sleep(5000); // Everything is processed and announced.
45+
46+
// Start all downloads (almost) simultaneously.
47+
var tasks = new List<Task>();
48+
foreach (var filePlan in plan.FilePlans)
49+
{
50+
foreach (var downloader in filePlan.Downloaders)
51+
{
52+
tasks.Add(Task.Run(() =>
53+
{
54+
var downloadedFile = downloader.Node!.DownloadContent(filePlan.Cid!);
55+
lock (filePlan.DownloadedFiles)
56+
{
57+
filePlan.DownloadedFiles.Add(downloadedFile);
58+
}
59+
}));
60+
}
61+
}
62+
63+
Task.WaitAll(tasks.ToArray());
64+
65+
// Assert all files are correct.
66+
foreach (var filePlan in plan.FilePlans)
67+
{
68+
foreach (var downloadedFile in filePlan.DownloadedFiles)
69+
{
70+
filePlan.File!.AssertIsEqual(downloadedFile);
71+
}
72+
}
73+
}
74+
75+
private Plan CreateThePlan(int numFiles, int uploadersPerFile, int downloadersPerFile, int maxUploadsPerNode, int maxDownloadsPerNode)
76+
{
77+
var plan = new Plan(numFiles, uploadersPerFile, downloadersPerFile, maxUploadsPerNode, maxDownloadsPerNode);
78+
plan.Initialize();
79+
plan.LogPlan(GetTestLog());
80+
return plan;
81+
}
82+
}
83+
84+
public class FilePlan
85+
{
86+
public FilePlan(int number)
87+
{
88+
Number = number;
89+
}
90+
91+
public int Number { get; }
92+
public TrackedFile? File { get; set; }
93+
public ContentId? Cid { get; set; }
94+
public List<TrackedFile?> DownloadedFiles { get; } = new List<TrackedFile?>();
95+
public List<NodePlan> Uploaders { get; } = new List<NodePlan>();
96+
public List<NodePlan> Downloaders { get; } = new List<NodePlan>();
97+
98+
public override string ToString()
99+
{
100+
return $"FilePlan[{Number}] " +
101+
$"Uploaders:[{string.Join(",", Uploaders.Select(u => u.Number.ToString()))}] " +
102+
$"Downloaders:[{string.Join(",", Downloaders.Select(u => u.Number.ToString()))}]";
103+
}
104+
}
105+
106+
public class NodePlan
107+
{
108+
public NodePlan(int number)
109+
{
110+
Number = number;
111+
}
112+
113+
public int Number { get; }
114+
public ICodexNode? Node { get; set; }
115+
public List<FilePlan> Uploads { get; } = new List<FilePlan>();
116+
public List<FilePlan> Downloads { get; } = new List<FilePlan>();
117+
118+
public bool Contains(FilePlan plan)
119+
{
120+
return Uploads.Contains(plan) || Downloads.Contains(plan);
121+
}
122+
123+
public override string ToString()
124+
{
125+
return $"NodePlan[{Number}] " +
126+
$"Uploads:[{string.Join(",", Uploads.Select(u => u.Number.ToString()))}] " +
127+
$"Downloads:[{string.Join(",", Downloads.Select(u => u.Number.ToString()))}]";
128+
}
129+
}
130+
131+
public class Plan
132+
{
133+
private readonly int numFiles;
134+
private readonly int uploadersPerFile;
135+
private readonly int downloadersPerFile;
136+
private readonly int maxUploadsPerNode;
137+
private readonly int maxDownloadsPerNode;
138+
139+
public Plan(int numFiles, int uploadersPerFile, int downloadersPerFile, int maxUploadsPerNode, int maxDownloadsPerNode)
140+
{
141+
this.numFiles = numFiles;
142+
this.uploadersPerFile = uploadersPerFile;
143+
this.downloadersPerFile = downloadersPerFile;
144+
this.maxUploadsPerNode = maxUploadsPerNode;
145+
this.maxDownloadsPerNode = maxDownloadsPerNode;
146+
}
147+
148+
public List<FilePlan> FilePlans { get; } = new List<FilePlan>();
149+
public List<NodePlan> NodePlans { get; } = new List<NodePlan>();
150+
151+
public void Initialize()
152+
{
153+
for (int i = 0; i < numFiles; i++) FilePlans.Add(new FilePlan(i));
154+
foreach (var filePlan in FilePlans)
155+
{
156+
while (filePlan.Uploaders.Count < uploadersPerFile) AddUploader(filePlan);
157+
while (filePlan.Downloaders.Count < downloadersPerFile) AddDownloader(filePlan);
158+
}
159+
160+
CollectionAssert.AllItemsAreUnique(FilePlans.Select(f => f.Number));
161+
CollectionAssert.AllItemsAreUnique(NodePlans.Select(f => f.Number));
162+
163+
foreach (var filePlan in FilePlans)
164+
{
165+
Assert.That(filePlan.Uploaders.Count, Is.EqualTo(uploadersPerFile));
166+
Assert.That(filePlan.Downloaders.Count, Is.EqualTo(downloadersPerFile));
167+
}
168+
foreach (var nodePlan in NodePlans)
169+
{
170+
Assert.That(nodePlan.Uploads.Count, Is.LessThanOrEqualTo(maxUploadsPerNode));
171+
Assert.That(nodePlan.Downloads.Count, Is.LessThanOrEqualTo(maxDownloadsPerNode));
172+
}
173+
}
174+
175+
public void LogPlan(ILog log)
176+
{
177+
log.Log("The plan:");
178+
log.Log("Input:");
179+
log.Log($"numFiles: {numFiles}");
180+
log.Log($"uploadersPerFile: {uploadersPerFile}");
181+
log.Log($"downloadersPerFile: {downloadersPerFile}");
182+
log.Log($"maxUploadsPerNode: {maxUploadsPerNode}");
183+
log.Log($"maxDownloadsPerNode: {maxDownloadsPerNode}");
184+
log.Log("Setup:");
185+
log.Log($"number of nodes: {NodePlans.Count}");
186+
foreach (var filePlan in FilePlans) log.Log(filePlan.ToString());
187+
foreach (var nodePlan in NodePlans) log.Log(nodePlan.ToString());
188+
}
189+
190+
private void AddDownloader(FilePlan filePlan)
191+
{
192+
var nodePlan = GetOrCreateDownloaderNode(filePlan);
193+
filePlan.Downloaders.Add(nodePlan);
194+
nodePlan.Downloads.Add(filePlan);
195+
}
196+
197+
private void AddUploader(FilePlan filePlan)
198+
{
199+
var nodePlan = GetOrCreateUploaderNode(filePlan);
200+
filePlan.Uploaders.Add(nodePlan);
201+
nodePlan.Uploads.Add(filePlan);
202+
}
203+
204+
private NodePlan GetOrCreateDownloaderNode(FilePlan notIn)
205+
{
206+
var available = NodePlans.Where(n =>
207+
n.Downloads.Count < maxDownloadsPerNode && !n.Contains(notIn)
208+
).ToArray();
209+
if (available.Any()) return RandomUtils.GetOneRandom(available);
210+
211+
var newNodePlan = new NodePlan(NodePlans.Count);
212+
NodePlans.Add(newNodePlan);
213+
return newNodePlan;
214+
}
215+
216+
private NodePlan GetOrCreateUploaderNode(FilePlan notIn)
217+
{
218+
var available = NodePlans.Where(n =>
219+
n.Uploads.Count < maxUploadsPerNode && !n.Contains(notIn)
220+
).ToArray();
221+
if (available.Any()) return RandomUtils.GetOneRandom(available);
222+
223+
var newNodePlan = new NodePlan(NodePlans.Count);
224+
NodePlans.Add(newNodePlan);
225+
return newNodePlan;
226+
}
227+
}
228+
}

0 commit comments

Comments
 (0)