Add upload tests
This commit is contained in:
1 parent
ff05bc89ed
commit
34315a1aca
7 files changed
+295
-46
No files matched your search
@@ -1,6 +1,5 @@
|
|||||||
namespace MyWebLog.Data.Postgres
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open BitBadger.Documents
|
|
||||||
open BitBadger.Documents.Postgres
|
open BitBadger.Documents.Postgres
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
@@ -41,7 +40,7 @@ type PostgresUploadData(log: ILogger) =
|
|||||||
(webLogIdParam webLogId :: idParam)
|
(webLogIdParam webLogId :: idParam)
|
||||||
(fun row -> row.string "path")
|
(fun row -> row.string "path")
|
||||||
if Option.isSome path then
|
if Option.isSome path then
|
||||||
do! Custom.nonQuery (Query.Delete.byId Table.Upload) idParam
|
do! Custom.nonQuery $"DELETE FROM {Table.Upload} WHERE id = @id" idParam
|
||||||
return Ok path.Value
|
return Ok path.Value
|
||||||
else return Error $"Upload ID {uploadId} not found"
|
else return Error $"Upload ID {uploadId} not found"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,33 +11,33 @@ open Npgsql
|
|||||||
open ThrowawayDb.Postgres
|
open ThrowawayDb.Postgres
|
||||||
|
|
||||||
/// JSON serializer
|
/// JSON serializer
|
||||||
let ser = Json.configure (JsonSerializer.CreateDefault())
|
let private ser = Json.configure (JsonSerializer.CreateDefault())
|
||||||
|
|
||||||
/// The throwaway database (deleted when disposed)
|
/// The throwaway database (deleted when disposed)
|
||||||
let mutable db: ThrowawayDatabase option = None
|
let mutable private db: ThrowawayDatabase option = None
|
||||||
|
|
||||||
/// Create a PostgresData instance for testing
|
/// Create a PostgresData instance for testing
|
||||||
let mkData () =
|
let private mkData () =
|
||||||
PostgresData(NullLogger<PostgresData>(), ser) :> IData
|
PostgresData(NullLogger<PostgresData>(), ser) :> IData
|
||||||
|
|
||||||
/// The host for the PostgreSQL test database (defaults to localhost)
|
/// The host for the PostgreSQL test database (defaults to localhost)
|
||||||
let testHost =
|
let private testHost =
|
||||||
RethinkDbDataTests.env "PG_HOST" "localhost"
|
RethinkDbDataTests.env "PG_HOST" "localhost"
|
||||||
|
|
||||||
/// The database name for the PostgreSQL test database (defaults to postgres)
|
/// The database name for the PostgreSQL test database (defaults to postgres)
|
||||||
let testDb =
|
let private testDb =
|
||||||
RethinkDbDataTests.env "PG_DB" "postgres"
|
RethinkDbDataTests.env "PG_DB" "postgres"
|
||||||
|
|
||||||
/// The user ID for the PostgreSQL test database (defaults to postgres)
|
/// The user ID for the PostgreSQL test database (defaults to postgres)
|
||||||
let testUser =
|
let private testUser =
|
||||||
RethinkDbDataTests.env "PG_USER" "postgres"
|
RethinkDbDataTests.env "PG_USER" "postgres"
|
||||||
|
|
||||||
/// The password for the PostgreSQL test database (defaults to postgres)
|
/// The password for the PostgreSQL test database (defaults to postgres)
|
||||||
let testPw =
|
let private testPw =
|
||||||
RethinkDbDataTests.env "PG_PW" "postgres"
|
RethinkDbDataTests.env "PG_PW" "postgres"
|
||||||
|
|
||||||
/// Create a fresh environment from the root backup
|
/// Create a fresh environment from the root backup
|
||||||
let freshEnvironment () = task {
|
let private freshEnvironment () = task {
|
||||||
if Option.isSome db then db.Value.Dispose()
|
if Option.isSome db then db.Value.Dispose()
|
||||||
db <- Some (ThrowawayDatabase.Create $"Host={testHost};Database={testDb};User ID={testUser};Password={testPw}")
|
db <- Some (ThrowawayDatabase.Create $"Host={testHost};Database={testDb};User ID={testUser};Password={testPw}")
|
||||||
let source = NpgsqlDataSourceBuilder db.Value.ConnectionString
|
let source = NpgsqlDataSourceBuilder db.Value.ConnectionString
|
||||||
@@ -50,12 +50,12 @@ let freshEnvironment () = task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set up the environment for the PostgreSQL tests
|
/// Set up the environment for the PostgreSQL tests
|
||||||
let environmentSetUp = testTask "creating database" {
|
let private environmentSetUp = testTask "creating database" {
|
||||||
do! freshEnvironment ()
|
do! freshEnvironment ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Integration tests for the Category implementation in PostgreSQL
|
/// Integration tests for the Category implementation in PostgreSQL
|
||||||
let categoryTests = testList "Category" [
|
let private categoryTests = testList "Category" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
do! CategoryDataTests.``Add succeeds`` (mkData ())
|
do! CategoryDataTests.``Add succeeds`` (mkData ())
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ let categoryTests = testList "Category" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Page implementation in PostgreSQL
|
/// Integration tests for the Page implementation in PostgreSQL
|
||||||
let pageTests = testList "Page" [
|
let private pageTests = testList "Page" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
do! PageDataTests.``Add succeeds`` (mkData ())
|
do! PageDataTests.``Add succeeds`` (mkData ())
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ let pageTests = testList "Page" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Post implementation in PostgreSQL
|
/// Integration tests for the Post implementation in PostgreSQL
|
||||||
let postTests = testList "Post" [
|
let private postTests = testList "Post" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
// We'll need the root website categories restored for these tests
|
// We'll need the root website categories restored for these tests
|
||||||
do! freshEnvironment ()
|
do! freshEnvironment ()
|
||||||
@@ -358,7 +358,7 @@ let postTests = testList "Post" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let tagMapTests = testList "TagMap" [
|
let private tagMapTests = testList "TagMap" [
|
||||||
testList "FindById" [
|
testList "FindById" [
|
||||||
testTask "succeeds when a tag mapping is found" {
|
testTask "succeeds when a tag mapping is found" {
|
||||||
do! TagMapDataTests.``FindById succeeds when a tag mapping is found`` (mkData ())
|
do! TagMapDataTests.``FindById succeeds when a tag mapping is found`` (mkData ())
|
||||||
@@ -416,7 +416,7 @@ let tagMapTests = testList "TagMap" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeTests = testList "Theme" [
|
let private themeTests = testList "Theme" [
|
||||||
testTask "All succeeds" {
|
testTask "All succeeds" {
|
||||||
do! ThemeDataTests.``All succeeds`` (mkData ())
|
do! ThemeDataTests.``All succeeds`` (mkData ())
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,7 @@ let themeTests = testList "Theme" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeAssetTests = testList "ThemeAsset" [
|
let private themeAssetTests = testList "ThemeAsset" [
|
||||||
testList "Save" [
|
testList "Save" [
|
||||||
testTask "succeeds when adding an asset" {
|
testTask "succeeds when adding an asset" {
|
||||||
do! ThemeDataTests.Asset.``Save succeeds when adding an asset`` (mkData ())
|
do! ThemeDataTests.Asset.``Save succeeds when adding an asset`` (mkData ())
|
||||||
@@ -508,8 +508,49 @@ let themeAssetTests = testList "ThemeAsset" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let private uploadTests = testList "Upload" [
|
||||||
|
testTask "Add succeeds" {
|
||||||
|
do! UploadDataTests.``Add succeeds`` (mkData ())
|
||||||
|
}
|
||||||
|
testList "FindByPath" [
|
||||||
|
testTask "succeeds when an upload is found" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is found`` (mkData ())
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (incorrect weblog)" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is not found (incorrect weblog)`` (mkData ())
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (bad path)" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is not found (bad path)`` (mkData ())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLog" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLog succeeds when uploads exist`` (mkData ())
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLog succeeds when no uploads exist`` (mkData ())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLogWithData" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLogWithData succeeds when uploads exist`` (mkData ())
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLogWithData succeeds when no uploads exist`` (mkData ())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "Delete" [
|
||||||
|
testTask "succeeds when an upload is deleted" {
|
||||||
|
do! UploadDataTests.``Delete succeeds when an upload is deleted`` (mkData ())
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not deleted" {
|
||||||
|
do! UploadDataTests.``Delete succeeds when an upload is not deleted`` (mkData ())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
/// Drop the throwaway PostgreSQL database
|
/// Drop the throwaway PostgreSQL database
|
||||||
let environmentCleanUp = test "Clean Up" {
|
let private environmentCleanUp = test "Clean Up" {
|
||||||
if db.IsSome then db.Value.Dispose()
|
if db.IsSome then db.Value.Dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,5 +564,6 @@ let all =
|
|||||||
tagMapTests
|
tagMapTests
|
||||||
themeTests
|
themeTests
|
||||||
themeAssetTests
|
themeAssetTests
|
||||||
|
uploadTests
|
||||||
environmentCleanUp ]
|
environmentCleanUp ]
|
||||||
|> testSequenced
|
|> testSequenced
|
||||||
@@ -18,14 +18,14 @@ let env name value =
|
|||||||
|
|
||||||
|
|
||||||
/// The data configuration for the test database
|
/// The data configuration for the test database
|
||||||
let dataCfg =
|
let private dataCfg =
|
||||||
DataConfig.FromUri (env "RETHINK_URI" "rethinkdb://172.17.0.2/mwl_test")
|
DataConfig.FromUri (env "RETHINK_URI" "rethinkdb://172.17.0.2/mwl_test")
|
||||||
|
|
||||||
/// The active data instance to use for testing
|
/// The active data instance to use for testing
|
||||||
let mutable data: IData option = None
|
let mutable private data: IData option = None
|
||||||
|
|
||||||
/// Dispose the existing data
|
/// Dispose the existing data
|
||||||
let disposeData () = task {
|
let private disposeData () = task {
|
||||||
if data.IsSome then
|
if data.IsSome then
|
||||||
let conn = (data.Value :?> RethinkDbData).Conn
|
let conn = (data.Value :?> RethinkDbData).Conn
|
||||||
do! rethink { dbDrop dataCfg.Database; write; withRetryOnce; ignoreResult conn }
|
do! rethink { dbDrop dataCfg.Database; write; withRetryOnce; ignoreResult conn }
|
||||||
@@ -34,13 +34,13 @@ let disposeData () = task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new data implementation instance
|
/// Create a new data implementation instance
|
||||||
let newData () =
|
let private newData () =
|
||||||
let log = NullLogger<RethinkDbData>()
|
let log = NullLogger<RethinkDbData>()
|
||||||
let conn = dataCfg.CreateConnection log
|
let conn = dataCfg.CreateConnection log
|
||||||
RethinkDbData(conn, dataCfg, log)
|
RethinkDbData(conn, dataCfg, log)
|
||||||
|
|
||||||
/// Create a fresh environment from the root backup
|
/// Create a fresh environment from the root backup
|
||||||
let freshEnvironment () = task {
|
let private freshEnvironment () = task {
|
||||||
do! disposeData ()
|
do! disposeData ()
|
||||||
data <- Some (newData ())
|
data <- Some (newData ())
|
||||||
do! data.Value.StartUp()
|
do! data.Value.StartUp()
|
||||||
@@ -49,13 +49,13 @@ let freshEnvironment () = task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set up the environment for the RethinkDB tests
|
/// Set up the environment for the RethinkDB tests
|
||||||
let environmentSetUp = testTask "creating database" {
|
let private environmentSetUp = testTask "creating database" {
|
||||||
let _ = Json.configure Converter.Serializer
|
let _ = Json.configure Converter.Serializer
|
||||||
do! freshEnvironment ()
|
do! freshEnvironment ()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Integration tests for the Category implementation in RethinkDB
|
/// Integration tests for the Category implementation in RethinkDB
|
||||||
let categoryTests = testList "Category" [
|
let private categoryTests = testList "Category" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
do! CategoryDataTests.``Add succeeds`` data.Value
|
do! CategoryDataTests.``Add succeeds`` data.Value
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ let categoryTests = testList "Category" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Page implementation in RethinkDB
|
/// Integration tests for the Page implementation in RethinkDB
|
||||||
let pageTests = testList "Page" [
|
let private pageTests = testList "Page" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
do! PageDataTests.``Add succeeds`` data.Value
|
do! PageDataTests.``Add succeeds`` data.Value
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ let pageTests = testList "Page" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Post implementation in RethinkDB
|
/// Integration tests for the Post implementation in RethinkDB
|
||||||
let postTests = testList "Post" [
|
let private postTests = testList "Post" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
// We'll need the root website categories restored for these tests
|
// We'll need the root website categories restored for these tests
|
||||||
do! freshEnvironment ()
|
do! freshEnvironment ()
|
||||||
@@ -358,7 +358,7 @@ let postTests = testList "Post" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let tagMapTests = testList "TagMap" [
|
let private tagMapTests = testList "TagMap" [
|
||||||
testList "FindById" [
|
testList "FindById" [
|
||||||
testTask "succeeds when a tag mapping is found" {
|
testTask "succeeds when a tag mapping is found" {
|
||||||
do! TagMapDataTests.``FindById succeeds when a tag mapping is found`` data.Value
|
do! TagMapDataTests.``FindById succeeds when a tag mapping is found`` data.Value
|
||||||
@@ -416,7 +416,7 @@ let tagMapTests = testList "TagMap" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeTests = testList "Theme" [
|
let private themeTests = testList "Theme" [
|
||||||
testTask "All succeeds" {
|
testTask "All succeeds" {
|
||||||
do! ThemeDataTests.``All succeeds`` data.Value
|
do! ThemeDataTests.``All succeeds`` data.Value
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,7 @@ let themeTests = testList "Theme" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeAssetTests = testList "ThemeAsset" [
|
let private themeAssetTests = testList "ThemeAsset" [
|
||||||
testList "Save" [
|
testList "Save" [
|
||||||
testTask "succeeds when adding an asset" {
|
testTask "succeeds when adding an asset" {
|
||||||
do! ThemeDataTests.Asset.``Save succeeds when adding an asset`` data.Value
|
do! ThemeDataTests.Asset.``Save succeeds when adding an asset`` data.Value
|
||||||
@@ -508,8 +508,49 @@ let themeAssetTests = testList "ThemeAsset" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let private uploadTests = testList "Upload" [
|
||||||
|
testTask "Add succeeds" {
|
||||||
|
do! UploadDataTests.``Add succeeds`` data.Value
|
||||||
|
}
|
||||||
|
testList "FindByPath" [
|
||||||
|
testTask "succeeds when an upload is found" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is found`` data.Value
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (incorrect weblog)" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is not found (incorrect weblog)`` data.Value
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (bad path)" {
|
||||||
|
do! UploadDataTests.``FindByPath succeeds when an upload is not found (bad path)`` data.Value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLog" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLog succeeds when uploads exist`` data.Value
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLog succeeds when no uploads exist`` data.Value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLogWithData" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLogWithData succeeds when uploads exist`` data.Value
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
do! UploadDataTests.``FindByWebLogWithData succeeds when no uploads exist`` data.Value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "Delete" [
|
||||||
|
testTask "succeeds when an upload is deleted" {
|
||||||
|
do! UploadDataTests.``Delete succeeds when an upload is deleted`` data.Value
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not deleted" {
|
||||||
|
do! UploadDataTests.``Delete succeeds when an upload is not deleted`` data.Value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
/// Drop the throwaway RethinkDB database
|
/// Drop the throwaway RethinkDB database
|
||||||
let environmentCleanUp = testTask "Clean Up" {
|
let private environmentCleanUp = testTask "Clean Up" {
|
||||||
do! disposeData ()
|
do! disposeData ()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,5 +564,6 @@ let all =
|
|||||||
tagMapTests
|
tagMapTests
|
||||||
themeTests
|
themeTests
|
||||||
themeAssetTests
|
themeAssetTests
|
||||||
|
uploadTests
|
||||||
environmentCleanUp ]
|
environmentCleanUp ]
|
||||||
|> testSequenced
|
|> testSequenced
|
||||||
@@ -10,20 +10,20 @@ open MyWebLog.Data
|
|||||||
open Newtonsoft.Json
|
open Newtonsoft.Json
|
||||||
|
|
||||||
/// JSON serializer
|
/// JSON serializer
|
||||||
let ser = Json.configure (JsonSerializer.CreateDefault())
|
let private ser = Json.configure (JsonSerializer.CreateDefault())
|
||||||
|
|
||||||
/// The test database name
|
/// The test database name
|
||||||
let dbName =
|
let private dbName =
|
||||||
RethinkDbDataTests.env "SQLITE_DB" "test-db.db"
|
RethinkDbDataTests.env "SQLITE_DB" "test-db.db"
|
||||||
|
|
||||||
/// Create a SQLiteData instance for testing
|
/// Create a SQLiteData instance for testing
|
||||||
let mkData () =
|
let private mkData () =
|
||||||
Configuration.useConnectionString $"Data Source=./{dbName}"
|
Configuration.useConnectionString $"Data Source=./{dbName}"
|
||||||
let conn = Configuration.dbConn ()
|
let conn = Configuration.dbConn ()
|
||||||
SQLiteData(conn, NullLogger<SQLiteData>(), ser) :> IData
|
SQLiteData(conn, NullLogger<SQLiteData>(), ser) :> IData
|
||||||
|
|
||||||
// /// Create a SQLiteData instance for testing
|
// /// Create a SQLiteData instance for testing
|
||||||
// let mkTraceData () =
|
// let private mkTraceData () =
|
||||||
// Sqlite.Configuration.useConnectionString $"Data Source=./{dbName}"
|
// Sqlite.Configuration.useConnectionString $"Data Source=./{dbName}"
|
||||||
// let conn = Sqlite.Configuration.dbConn ()
|
// let conn = Sqlite.Configuration.dbConn ()
|
||||||
// let myLogger =
|
// let myLogger =
|
||||||
@@ -37,11 +37,11 @@ let mkData () =
|
|||||||
// SQLiteData(conn, myLogger, ser) :> IData
|
// SQLiteData(conn, myLogger, ser) :> IData
|
||||||
|
|
||||||
/// Dispose the connection associated with the SQLiteData instance
|
/// Dispose the connection associated with the SQLiteData instance
|
||||||
let dispose (data: IData) =
|
let private dispose (data: IData) =
|
||||||
(data :?> SQLiteData).Conn.Dispose()
|
(data :?> SQLiteData).Conn.Dispose()
|
||||||
|
|
||||||
/// Create a fresh environment from the root backup
|
/// Create a fresh environment from the root backup
|
||||||
let freshEnvironment (data: IData option) = task {
|
let private freshEnvironment (data: IData option) = task {
|
||||||
let! env = task {
|
let! env = task {
|
||||||
match data with
|
match data with
|
||||||
| Some d ->
|
| Some d ->
|
||||||
@@ -63,7 +63,7 @@ let freshEnvironment (data: IData option) = task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set up the environment for the SQLite tests
|
/// Set up the environment for the SQLite tests
|
||||||
let environmentSetUp = testList "Environment" [
|
let private environmentSetUp = testList "Environment" [
|
||||||
testTask "creating database" {
|
testTask "creating database" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
try do! freshEnvironment (Some data)
|
try do! freshEnvironment (Some data)
|
||||||
@@ -72,7 +72,7 @@ let environmentSetUp = testList "Environment" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Category implementation in SQLite
|
/// Integration tests for the Category implementation in SQLite
|
||||||
let categoryTests = testList "Category" [
|
let private categoryTests = testList "Category" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
try do! CategoryDataTests.``Add succeeds`` data
|
try do! CategoryDataTests.``Add succeeds`` data
|
||||||
@@ -166,7 +166,7 @@ let categoryTests = testList "Category" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Page implementation in SQLite
|
/// Integration tests for the Page implementation in SQLite
|
||||||
let pageTests = testList "Page" [
|
let private pageTests = testList "Page" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
try do! PageDataTests.``Add succeeds`` data
|
try do! PageDataTests.``Add succeeds`` data
|
||||||
@@ -320,7 +320,7 @@ let pageTests = testList "Page" [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/// Integration tests for the Post implementation in SQLite
|
/// Integration tests for the Post implementation in SQLite
|
||||||
let postTests = testList "Post" [
|
let private postTests = testList "Post" [
|
||||||
testTask "Add succeeds" {
|
testTask "Add succeeds" {
|
||||||
// We'll need the root website categories restored for these tests
|
// We'll need the root website categories restored for these tests
|
||||||
let! data = freshEnvironment None
|
let! data = freshEnvironment None
|
||||||
@@ -530,7 +530,7 @@ let postTests = testList "Post" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let tagMapTests = testList "TagMap" [
|
let private tagMapTests = testList "TagMap" [
|
||||||
testList "FindById" [
|
testList "FindById" [
|
||||||
testTask "succeeds when a tag mapping is found" {
|
testTask "succeeds when a tag mapping is found" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
@@ -615,7 +615,7 @@ let tagMapTests = testList "TagMap" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeTests = testList "Theme" [
|
let private themeTests = testList "Theme" [
|
||||||
testTask "All succeeds" {
|
testTask "All succeeds" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
try do! ThemeDataTests.``All succeeds`` data
|
try do! ThemeDataTests.``All succeeds`` data
|
||||||
@@ -683,7 +683,7 @@ let themeTests = testList "Theme" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
let themeAssetTests = testList "ThemeAsset" [
|
let private themeAssetTests = testList "ThemeAsset" [
|
||||||
testList "Save" [
|
testList "Save" [
|
||||||
testTask "succeeds when adding an asset" {
|
testTask "succeeds when adding an asset" {
|
||||||
let data = mkData ()
|
let data = mkData ()
|
||||||
@@ -751,8 +751,69 @@ let themeAssetTests = testList "ThemeAsset" [
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
let private uploadTests = testList "Upload" [
|
||||||
|
testTask "Add succeeds" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``Add succeeds`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testList "FindByPath" [
|
||||||
|
testTask "succeeds when an upload is found" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByPath succeeds when an upload is found`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (incorrect weblog)" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByPath succeeds when an upload is not found (incorrect weblog)`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not found (bad path)" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByPath succeeds when an upload is not found (bad path)`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLog" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByWebLog succeeds when uploads exist`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByWebLog succeeds when no uploads exist`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "FindByWebLogWithData" [
|
||||||
|
testTask "succeeds when uploads exist" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByWebLogWithData succeeds when uploads exist`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testTask "succeeds when no uploads exist" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``FindByWebLogWithData succeeds when no uploads exist`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
testList "Delete" [
|
||||||
|
testTask "succeeds when an upload is deleted" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``Delete succeeds when an upload is deleted`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
testTask "succeeds when an upload is not deleted" {
|
||||||
|
let data = mkData ()
|
||||||
|
try do! UploadDataTests.``Delete succeeds when an upload is not deleted`` data
|
||||||
|
finally dispose data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
/// Delete the SQLite database
|
/// Delete the SQLite database
|
||||||
let environmentCleanUp = test "Clean Up" {
|
let private environmentCleanUp = test "Clean Up" {
|
||||||
File.Delete dbName
|
File.Delete dbName
|
||||||
Expect.isFalse (File.Exists dbName) "The test SQLite database should have been deleted"
|
Expect.isFalse (File.Exists dbName) "The test SQLite database should have been deleted"
|
||||||
}
|
}
|
||||||
@@ -767,5 +828,6 @@ let all =
|
|||||||
tagMapTests
|
tagMapTests
|
||||||
themeTests
|
themeTests
|
||||||
themeAssetTests
|
themeAssetTests
|
||||||
|
uploadTests
|
||||||
environmentCleanUp ]
|
environmentCleanUp ]
|
||||||
|> testSequenced
|
|> testSequenced
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/// <summary>
|
||||||
|
/// Integration tests for <see cref="IUploadData" /> implementations
|
||||||
|
/// </summary>
|
||||||
|
module UploadDataTests
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open Expecto
|
||||||
|
open MyWebLog
|
||||||
|
open MyWebLog.Data
|
||||||
|
open NodaTime
|
||||||
|
|
||||||
|
/// The ID of the root web log
|
||||||
|
let private rootId = CategoryDataTests.rootId
|
||||||
|
|
||||||
|
/// The ID of the favicon upload
|
||||||
|
let private faviconId = UploadId "XweKbWQiOkqqrjEdgP9wwg"
|
||||||
|
|
||||||
|
let ``Add succeeds`` (data: IData) = task {
|
||||||
|
let file = File.ReadAllBytes "../admin-theme/wwwroot/logo-dark.png"
|
||||||
|
do! data.Upload.Add
|
||||||
|
{ Id = UploadId "new-upload"
|
||||||
|
WebLogId = rootId
|
||||||
|
UpdatedOn = Noda.epoch + Duration.FromDays 30
|
||||||
|
Path = Permalink "1970/01/logo-dark.png"
|
||||||
|
Data = file }
|
||||||
|
let! added = data.Upload.FindByPath "1970/01/logo-dark.png" rootId
|
||||||
|
Expect.isSome added "There should have been an upload returned"
|
||||||
|
let upload = added.Value
|
||||||
|
Expect.equal upload.Id (UploadId "new-upload") "ID is incorrect"
|
||||||
|
Expect.equal upload.WebLogId rootId "Web log ID is incorrect"
|
||||||
|
Expect.equal upload.UpdatedOn (Noda.epoch + Duration.FromDays 30) "Updated on is incorrect"
|
||||||
|
Expect.equal upload.Path (Permalink "1970/01/logo-dark.png") "Path is incorrect"
|
||||||
|
Expect.equal upload.Data file "Data is incorrect"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByPath succeeds when an upload is found`` (data: IData) = task {
|
||||||
|
let! upload = data.Upload.FindByPath "2022/06/favicon.ico" rootId
|
||||||
|
Expect.isSome upload "There should have been an upload returned"
|
||||||
|
let it = upload.Value
|
||||||
|
Expect.equal it.Id faviconId "ID is incorrect"
|
||||||
|
Expect.equal it.WebLogId rootId "Web log ID is incorrect"
|
||||||
|
Expect.equal
|
||||||
|
it.UpdatedOn (Instant.FromDateTimeOffset(DateTimeOffset.Parse "2022-06-23T21:15:40Z")) "Updated on is incorrect"
|
||||||
|
Expect.equal it.Path (Permalink "2022/06/favicon.ico") "Path is incorrect"
|
||||||
|
Expect.isNonEmpty it.Data "Data should have been retrieved"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByPath succeeds when an upload is not found (incorrect weblog)`` (data: IData) = task {
|
||||||
|
let! upload = data.Upload.FindByPath "2022/06/favicon.ico" (WebLogId "wrong")
|
||||||
|
Expect.isNone upload "There should not have been an upload returned"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByPath succeeds when an upload is not found (bad path)`` (data: IData) = task {
|
||||||
|
let! upload = data.Upload.FindByPath "2022/07/favicon.ico" rootId
|
||||||
|
Expect.isNone upload "There should not have been an upload returned"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByWebLog succeeds when uploads exist`` (data: IData) = task {
|
||||||
|
let! uploads = data.Upload.FindByWebLog rootId
|
||||||
|
Expect.hasLength uploads 2 "There should have been 2 uploads returned"
|
||||||
|
for upload in uploads do
|
||||||
|
Expect.contains [ faviconId; UploadId "new-upload" ] upload.Id $"Unexpected upload returned ({upload.Id})"
|
||||||
|
Expect.isEmpty upload.Data $"Upload should not have had its data ({upload.Id})"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByWebLog succeeds when no uploads exist`` (data: IData) = task {
|
||||||
|
let! uploads = data.Upload.FindByWebLog (WebLogId "nothing")
|
||||||
|
Expect.isEmpty uploads "There should have been no uploads returned"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByWebLogWithData succeeds when uploads exist`` (data: IData) = task {
|
||||||
|
let! uploads = data.Upload.FindByWebLogWithData rootId
|
||||||
|
Expect.hasLength uploads 2 "There should have been 2 uploads returned"
|
||||||
|
for upload in uploads do
|
||||||
|
Expect.contains [ faviconId; UploadId "new-upload" ] upload.Id $"Unexpected upload returned ({upload.Id})"
|
||||||
|
Expect.isNonEmpty upload.Data $"Upload should have had its data ({upload.Id})"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``FindByWebLogWithData succeeds when no uploads exist`` (data: IData) = task {
|
||||||
|
let! uploads = data.Upload.FindByWebLogWithData (WebLogId "data-nope")
|
||||||
|
Expect.isEmpty uploads "There should have been no uploads returned"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``Delete succeeds when an upload is deleted`` (data: IData) = task {
|
||||||
|
match! data.Upload.Delete faviconId rootId with
|
||||||
|
| Ok path -> Expect.equal path "2022/06/favicon.ico" "The path of the deleted upload was incorrect"
|
||||||
|
| Error it -> Expect.isTrue false $"Upload deletion should have succeeded (message {it})"
|
||||||
|
}
|
||||||
|
|
||||||
|
let ``Delete succeeds when an upload is not deleted`` (data: IData) = task {
|
||||||
|
match! data.Upload.Delete faviconId rootId with
|
||||||
|
| Ok it -> Expect.isTrue false $"Upload deletion should not have succeeded (path {it})"
|
||||||
|
| Error msg -> Expect.equal msg $"Upload ID {faviconId} not found" "Error message was incorrect"
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
<Compile Include="Data\PostDataTests.fs" />
|
<Compile Include="Data\PostDataTests.fs" />
|
||||||
<Compile Include="Data\TagMapDataTests.fs" />
|
<Compile Include="Data\TagMapDataTests.fs" />
|
||||||
<Compile Include="Data\ThemeDataTests.fs" />
|
<Compile Include="Data\ThemeDataTests.fs" />
|
||||||
|
<Compile Include="Data\UploadDataTests.fs" />
|
||||||
<Compile Include="Data\RethinkDbDataTests.fs" />
|
<Compile Include="Data\RethinkDbDataTests.fs" />
|
||||||
<Compile Include="Data\SQLiteDataTests.fs" />
|
<Compile Include="Data\SQLiteDataTests.fs" />
|
||||||
<Compile Include="Data\PostgresDataTests.fs" />
|
<Compile Include="Data\PostgresDataTests.fs" />
|
||||||
|
|||||||
@@ -368,5 +368,13 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Uploads": []
|
"Uploads": [
|
||||||
|
{
|
||||||
|
"Id": "XweKbWQiOkqqrjEdgP9wwg",
|
||||||
|
"WebLogId": "uSitJEuD3UyzWC9jgOHc8g",
|
||||||
|
"Path": "2022/06/favicon.ico",
|
||||||
|
"UpdatedOn": "2022-06-23T21:15:40Z",
|
||||||
|
"Data": "AAABAAQAEBAAAAEACACrAgAARgAAABgYAAABABgA8QQAAPECAAAgIAAAAQAYAJ8HAADiBwAAQEAAAAEAGAC3FQAAgQ8AAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAnJJREFUOI2Nkb1rU2EUxn/nvDc3uTGxqdaPtipVo2L8GLQUcRAVRVAEEfwLFFyquLgI0sHNQZFuDoIUCi46iCgqrh0Lgk5KbWuTkFTz1SSmt/e+DrcVpUM98JyXl8N5eM7zyMRE3qoKooIAD0efk93rsGdgPXuyA6xVTr7QRo0gIqiAtS6eF6daraC6a22CQqmDqkQQwQ8cPC9OvVpERNYmKJZ8RAWjkYpFP0Y87lILLKr6HwrKS6jIHxWtTgw37hKErCKo1Wv4vk/Pxp6/TwgxKqiCqLDQdoi7MYIQrLVUKj8pFOZoNBf48O4tmUyG02fOUa/XeP/2NU5x3mKWl1Us7uJHEvGTdDqLlMslxseeUirk8X2fhJcglU7z4tk4jXqDzq82TnF+OQEFYyxnuyaYm06zb3cPjx7cZ+j4cbLZLO12m2IxT35mllq1yoq9YrZPWpFIAQBBhdGRr1y5fImu9RmMMQBYLKUfRX7O/6BaqzHzbZowDBDZ8dlGVFGzfpM3Yz5fvkzxfWqSwPfp6s4QBAH92/oZOnYMz/Ow1hKGIQ4msbId1ZJgTIWDh4/Qv9kjl8v9Gb15/Yrhq9e4fvMGBw4dolGr4FiTWLkmeoyh9avOppRLs9n6J8rzFy5y5Ogg9+7ewVrLho0bUNTjH5gUzZbixl0skcF/o7e3j9HHT/CSSebLJVS1RXe6ys6+IoO5AqdO5PGSHq7rImJQ1VWIOQ53Ru6RTK3D+fTSx5gYYjxEDCKKvyQYJ4aog6gigLUgEqUhCFu3bGX41m0cqylCMdjAkp+bZXZminK5TLPZondTetkDiyJYLEr0xwr79x/gNzoU7W4mtXWQAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAEuElEQVRIiZ2Uy4scVRTGf+fcW1X9mGmT6WRIJqPmpdFEBUMwIELEB1kEdZFFcOlCUBE3gq5cCAE3+Qtc+EREd6IbcSPBB75FUYwzmUwmiZlJMv2Yqe7prqp7r4vumYxGBVNwoYq6nN/9vvudI19/fTGICCIgIthImZ1t88ZbJ9m9p0PwGZvrCYfuO8D1PLbZyhARVARRMEbpdBzGxjjXpVqtEEJBURREUfT/Aa1WhuhVBcYInY5HNcZ5oVKpglui3+8Tx/F1KGgXiA6Kq4JRJe16EIt3QqVSpru0TK/Xo1arXQdgqRjYI6AqqHrSjscT4ZwZ2CJCv99HRP4/oNV26NAeFUGM0Ot5nDM4b7DWEkRwzl0nYMkPAas2CVkeyJzivCWKDAQhBPlXQHelS/CeanXkb39kAFgtLhpQEZyDLDc4b7GRBRF8CGuANE1RI4BwaWGBH374lhAChw8fIQSP94E8zzh9egrbHCpQ0QFIIQToZYrzhsiagbwA3W4HBC5fnmdu7ixpmrK42KDZuEJSKjE19RuI0Gw0mJ2Z5szpaWxrGRQQCcO4BjT0oD9L1nXE0TYExQdPo9lg6tRvXDg/x+zpGVa6XcqVChvGNlIql/n1l5/ppintZosL58+hKtjW0tCe1SQJlLXF7fEnjJst9Hqb2TZxA520wffffMHcubPMzcxgjSXr9ymKAjOrVEZrVMol0qUlBEFVcR5sc0nWADq8g5SEejlmnMssXJim3WwxdeoUCwvzHLz3Xo4de5yxsTpFXjC/8AfT01PMTE9zfu4cnW4Xo2btviS++fsgg/ta6wfnHdaf55FDZ3jwUIXdO3cxtrFOqVSivmkT9fqmtZz08y5n584yf3GexStXaCwu0lhs4JwDAjb3djVRgCBACBFZuJE01Ng6qVxaXOannz5lud0ispakVGK0NsrWyW3cvf9uNtbrJEmJiclJXFHQ7/cJIRBCwKLx+tgSYJB7B7lLKJcjen1FTJUtE1W6nQ7GGHwQvvr8S95+7XX23rmP+w7dz/bt2/HOkSQJIQS8c1g0Yp2Eq6+FkLsIY4Sx+mY67QV2bt/Chg0bCMOeyPYfYH7+Ih99+AEnjh/nrv37eezoUcbHx+l2OqTLbWz4JwACquQuxntHFFsQJc9zkiRZ25UkCSOjozz9zLN8dvIk77/7Nj9+9x0Tk5PsuW0P45vHsEi8rvY6iBqKEFP4HpXIIqp4H64ZFwKUyxUeeOhhduzcyYlXjjNz6nfO/D6FsRZFI5C/LY3AxDg/mKg2sojoun65dllr2X3Lrbz40suYyA7SWOQoGnN1DYqLRqAJLsQUhRJFFtHByPgviKqyY8cOnnv+BTSyJKUEO76xSTXJqZQdI+WC0aqjNhKolj27bhJGayMYtaiaNRWr1oS/GDX4Msawb+8dPPHkU7z3zpvYj1/NUGMwJkLUoqoABIQQwHtQoxhjBn0ybMbhpnW15Wo+xHLgwEEuXVrA2qT2F+nOe5xzeF/gnSMEj6oly3JEysjwAITBkEUCghAkIEHWOEkSc+TIo1hrDVmW02q3WF5u0Wq2SNNlVlZWWOn1yPoZBAeh4OaJe1CR4YHDsO8HxRUdFh/KEiFJSvwJAgAKftfyeo4AAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAdmSURBVFiFpZdrjF1VFcd/a+99z3105k5n2qGBIa1t0UBFAn3ED9AgtrQJoRCI8UGUT4ookRgNglETEhITP2iCMUJMIOKjgIiKgFS0RNsglnFKFZsUMh2gpe1M27kz0/uYe89r+eGce8+9M1N87eRmn7Pv3mv/13/999rryOjoKRURjAEQREAk6X0/ZutHHuHzXyiwfHCAXM7jwMu/4+v33p3MAZS0db2IgGr3uKTjmo2nf7paLUTSzY3Q86yAmDxhKFhrESv09Q8QhiGe53Xsd9nrPIhotrlkyDLYSe9q9RCEzHNSNgRyziLiEUYB1lqMGEp9ZaIoQqRna3rpyNCIgJJtnJAhnTmuWgt7aO/u83kolEoE/jmsNYgIff3nAbCIjqWGZdEUV6uHiEn+aG9OyoLvK/3lEn5QxVoLQN+ygfMD+B+aq9VjEDAdz+kY9zyl1LeMwKcDwFpLFMW0Bau0Q6xouk4UNI1zMqSoprro0QC4aj3CCKkODCKagEDI+VAsevihwVqLokiiUsQkBowqbQMdGYhiMF1+Zsy233sYyDzXJBQmYcFaxcvn8H2TMeBcEoKO7d5QtKH06PE9Q9CIOmdaDIhK5yg6J+Q8RyuwGGsQwPM8ZmZnGRm56D0Nd3C1T2CHHXpOi6vWQYgxRtIwaAeQtYq1Dj+wOGdRVfL5AmfPnPq3Ipybm+PdE8dQVdavu4RisZSAysJPo9FYGIL2SVAExVgBsfiBwZpEA17e48TJ6R4AYRhy+vQUMzMzjIyM0N9f5smnfs7xiQka802++KUvc8n69xOGIcYYxsff5MCrr/DawTFcrZHE3Qhg0hh2AYrU4gcO5yyxKoVCgbNnMwD79v+Za66+mpE1F3J6epIX9+5BEFavXsPWrVvxWz5RFHDs+Fv0lfs5efIkr42N8e7bb+ElGkg2b4u0EwIBYyCIWrQCEg3ESs45KtMVqtVz7N+/j8/cfjtP7N7N4z99DM85rEkSVhhHtIKA/sFBhoeHQZUzU1M0G3X6S32IEVQVV6snLpvUY7rzgU7y4dJjTBZjZiu3MrTyIqwxTM+cIV/IM7RikE987BZiP6BvWQmUznFzkqNYKBJHETt27uTRhx+mlC9QKpQI4wiiRKGyZvOoZrRLD/05jnHzBY9SzAlsuJxLNlyOs5bLLt3A0089yQvPPcvOm27i4OgB5qYr9PeXqddrNOoNcjmHcy4JlbUQhonROBMhgKzYMKrSThQpE+3LyRplvfkqHygrb4YtNFa8nMOJEEUxcRxTazb55G2f5o477qRQKIIqlZkKv//DC+x98UUO/+N18s5hTHdi6gLgrRnTtsemKwRGIAgBqgyX9vPAvSNct+1agmbExNGjzDcaDK9axcaNm8h7+UWG54M6zVaL2coMR944wltHJzhx7Dinp6bwfb+TJEQuPrQoabUV3i4eyqWz/Og7wugrf+TGXddz1ZUbsZhML8ZgJMmWsUT4fotWq8n8fJNWq0UYhqgqJhVo234cRYis/ud5smYWqLyd5iffCyj1Lefc7CyHDu7ntdE/YTTGWYvneTjnyBeLlAeXc9327Xx02zaq1RqtZpM4jpfcIY4jRNYc0YUbLp45yxPfr1IeWAnAbGWaWmWCwcEBTk1NUqtWKQ8MYIxhbPRV3jh8mDCO+Phtn2LTli2sWrVqEQiN4/Raf994L4AlcGjzHL/44RkGhy5EAedyHNj3a2695dbk2k2LQElLsPlWk2ef+RXP//YZSvk8F69byz333YeXzxNFEVEUEQY+vt/CyuBX7kcMKjYtCBf8xEAQc9P1cwwsX55USoUCfz/4Mhs3XpVdZNI+PpBzjg9e/iGu3LSZ8fFx3hkf5/lnn6NRbxDFMYW8R9BqcnZqEqfGLRn3nmY85urCamfRWHHGoJqJ9Xxt3dp13P/At3nooR8w9spfeGnPHl7as4cgjlm7fi1bNl+BQ1xPNbtksx5z1RjnDFGkGGtRNf9RWSYi3HXX3ey99DJ2//gRjBjyRjg+8TbvTLydAli0asGDUeaq4KyD9OrO5wvZcT0/9E7bvn0HQRDw9OM/Q8TgxKAoDrMQwBKmrOFczWCtoGIRY8gXSx0PF69YGtINN9xIFEU8/5tfJlWTxjjEy0oVVSBOem33CnFEtW4wxuDSj5ZisYSqnicMSbJRtPsbBAR27bqZycmTHD40Bqq45cWjDPW36F/WYrAcMViOGRqIGR6yDA85Vg4ZigVHubwKMRYjYMRQLC3rLine truncated
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user