160 lines
4.8 KiB
C#
160 lines
4.8 KiB
C#
using MongoDB.Bson;
|
|
using QuestionsApi.Services;
|
|
using Xunit;
|
|
|
|
namespace QuestionsApi.Tests;
|
|
|
|
public sealed class ContentPromotionTests
|
|
{
|
|
[Fact]
|
|
public void CollectMediaIdsDeduplicatesValidObjectIds()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
var questions = new[]
|
|
{
|
|
new BsonDocument("Media", new BsonArray { id.ToString(), "not-an-object-id" }),
|
|
new BsonDocument("Media", new BsonArray { id.ToString() })
|
|
};
|
|
|
|
var result = ContentPromotionCommand.CollectMediaIds(questions);
|
|
|
|
Assert.Equal(new[] { id }, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void ContentHashDoesNotDependOnInputOrder()
|
|
{
|
|
var first = new BsonDocument { ["ExternalId"] = "a", ["Stem"] = "one" };
|
|
var second = new BsonDocument { ["ExternalId"] = "b", ["Stem"] = "two" };
|
|
|
|
Assert.Equal(
|
|
ContentPromotionCommand.HashDocuments([first, second]),
|
|
ContentPromotionCommand.HashDocuments([second, first]));
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadyQuestionEligibilityRequiresPublishedAndUnflagged()
|
|
{
|
|
Assert.True(QuestionPromotionCommand.IsEligible(new BsonDocument
|
|
{
|
|
["IsPublished"] = true,
|
|
["FlaggedForReviewUtc"] = BsonNull.Value
|
|
}));
|
|
Assert.True(QuestionPromotionCommand.IsEligible(new BsonDocument("IsPublished", true)));
|
|
Assert.False(QuestionPromotionCommand.IsEligible(new BsonDocument
|
|
{
|
|
["IsPublished"] = true,
|
|
["FlaggedForReviewUtc"] = DateTime.UtcNow
|
|
}));
|
|
Assert.False(QuestionPromotionCommand.IsEligible(new BsonDocument("IsPublished", false)));
|
|
}
|
|
|
|
[Fact]
|
|
public void QuestionMediaIdsSupportStoredApiUrlsAndRawIds()
|
|
{
|
|
var first = ObjectId.GenerateNewId();
|
|
var second = ObjectId.GenerateNewId();
|
|
var questions = new[]
|
|
{
|
|
new BsonDocument
|
|
{
|
|
["ExternalId"] = "one",
|
|
["Media"] = new BsonArray { $"/api/questions/media/{first}", second.ToString() }
|
|
},
|
|
new BsonDocument
|
|
{
|
|
["ExternalId"] = "two",
|
|
["Media"] = new BsonArray { $"https://example.test/api/questions/media/{first}" }
|
|
}
|
|
};
|
|
|
|
var result = QuestionPromotionCommand.CollectMediaIds(questions);
|
|
|
|
Assert.Equal(new HashSet<ObjectId> { first, second }, result);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidLocalQuestionMediaReferenceFailsValidation()
|
|
{
|
|
var question = new BsonDocument
|
|
{
|
|
["ExternalId"] = "bad-media",
|
|
["Media"] = new BsonArray { "/api/questions/media/not-an-id" }
|
|
};
|
|
|
|
var exception = Assert.Throws<InvalidOperationException>(
|
|
() => QuestionPromotionCommand.CollectMediaIds([question]));
|
|
|
|
Assert.Contains("bad-media", exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void QuestionComparisonClassifiesInsertUpdateAndUnchanged()
|
|
{
|
|
var source = new[]
|
|
{
|
|
Question("insert", "new"),
|
|
Question("update", "new"),
|
|
Question("same", "same")
|
|
};
|
|
var target = new[]
|
|
{
|
|
Question("update", "old"),
|
|
new BsonDocument
|
|
{
|
|
["Stem"] = "same",
|
|
["ExternalId"] = "same",
|
|
["_id"] = ObjectId.GenerateNewId()
|
|
}
|
|
};
|
|
|
|
var result = QuestionPromotionCommand.ClassifyQuestions(source, target);
|
|
|
|
Assert.Equal(1, result.Inserted);
|
|
Assert.Equal(1, result.Updated);
|
|
Assert.Equal(1, result.Unchanged);
|
|
}
|
|
|
|
[Fact]
|
|
public void QuestionHashIgnoresMongoIdsFieldOrderAndInputOrder()
|
|
{
|
|
var first = Question("a", "one");
|
|
first["_id"] = ObjectId.GenerateNewId();
|
|
var second = Question("b", "two");
|
|
var equivalentFirst = new BsonDocument
|
|
{
|
|
["Stem"] = "one",
|
|
["_id"] = ObjectId.GenerateNewId(),
|
|
["ExternalId"] = "a"
|
|
};
|
|
|
|
Assert.Equal(
|
|
QuestionPromotionCommand.HashQuestions([first, second]),
|
|
QuestionPromotionCommand.HashQuestions([second, equivalentFirst]));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadyQuestionApplyRequiresExplicitProductionConfirmation()
|
|
{
|
|
using var output = new StringWriter();
|
|
|
|
var result = await QuestionPromotionCommand.RunAsync(
|
|
[
|
|
"--source-connection", "mongodb://source.invalid",
|
|
"--source-database", "uat",
|
|
"--target-connection", "mongodb://target.invalid",
|
|
"--target-database", "prd",
|
|
"--apply"
|
|
], output);
|
|
|
|
Assert.Equal(1, result);
|
|
Assert.Contains("--confirm PROMOTE_TO_PRD is required", output.ToString());
|
|
}
|
|
|
|
private static BsonDocument Question(string externalId, string stem) => new()
|
|
{
|
|
["ExternalId"] = externalId,
|
|
["Stem"] = stem
|
|
};
|
|
}
|