From d788f29d10d41ac765d0a23397c3db3210e137e3 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 12:16:00 +0200 Subject: [PATCH 01/19] move old backend inside old directory --- be1-go/cli/cli.go | 2 +- be1-go/cli/cli_test.go | 4 ++-- .../messagedata/coin_post_transaction.go | 2 +- be1-go/network/server.go | 2 +- be1-go/network/server_test.go | 4 ++-- .../channel/authentication/authentication.go | 6 ++--- .../authentication/authentication_test.go | 10 ++++----- be1-go/{ => old}/channel/channel.go | 0 be1-go/{ => old}/channel/chirp/chirp.go | 6 ++--- be1-go/{ => old}/channel/chirp/chirp_test.go | 8 +++---- be1-go/{ => old}/channel/coin/coin.go | 6 ++--- be1-go/{ => old}/channel/coin/coin_test.go | 4 ++-- .../{ => old}/channel/consensus/consensus.go | 6 ++--- .../channel/consensus/consensus_test.go | 4 ++-- .../channel/consensus/message_creation.go | 0 be1-go/{ => old}/channel/election/election.go | 6 ++--- .../channel/election/election_test.go | 6 ++--- .../channel/election/verification.go | 0 .../channel/election/verification_test.go | 0 .../generalChirping/generalChirping.go | 6 ++--- .../generalChirping/generalChirping_test.go | 4 ++-- be1-go/{ => old}/channel/lao/lao.go | 20 ++++++++--------- be1-go/{ => old}/channel/lao/lao_test.go | 4 ++-- be1-go/{ => old}/channel/lao/verification.go | 0 .../channel/lao/verification_test.go | 4 ++-- be1-go/{ => old}/channel/reaction/reaction.go | 6 ++--- .../channel/reaction/reaction_test.go | 4 ++-- be1-go/{ => old}/channel/registry/registry.go | 0 be1-go/{ => old}/hub/hub.go | 0 .../hub/standard_hub/hub_state/channels.go | 4 +++- .../hub/standard_hub/hub_state/messageIds.go | 0 .../hub/standard_hub/hub_state/peers.go | 0 .../hub/standard_hub/hub_state/queries.go | 0 .../standard_hub/hub_state/threadSafeMap.go | 0 .../standard_hub/hub_state/threadSafeSlice.go | 0 .../hub/standard_hub/message_handling.go | 2 +- .../hub/standard_hub/standard_hub.go | 22 +++++++++---------- .../hub/standard_hub/standard_hub_test.go | 4 ++-- be1-go/{ => old}/inbox/hub_inbox.go | 2 +- be1-go/{ => old}/inbox/inbox.go | 0 be1-go/{ => old}/inbox/inbox_test.go | 0 be1-go/popcha/server.go | 2 +- be1-go/popcha/server_test.go | 4 ++-- be1-go/{channel/coin => }/uint53/uint53.go | 0 .../{channel/coin => }/uint53/uint53_test.go | 0 45 files changed, 83 insertions(+), 81 deletions(-) rename be1-go/{ => old}/channel/authentication/authentication.go (99%) rename be1-go/{ => old}/channel/authentication/authentication_test.go (96%) rename be1-go/{ => old}/channel/channel.go (100%) rename be1-go/{ => old}/channel/chirp/chirp.go (99%) rename be1-go/{ => old}/channel/chirp/chirp_test.go (98%) rename be1-go/{ => old}/channel/coin/coin.go (98%) rename be1-go/{ => old}/channel/coin/coin_test.go (99%) rename be1-go/{ => old}/channel/consensus/consensus.go (99%) rename be1-go/{ => old}/channel/consensus/consensus_test.go (99%) rename be1-go/{ => old}/channel/consensus/message_creation.go (100%) rename be1-go/{ => old}/channel/election/election.go (99%) rename be1-go/{ => old}/channel/election/election_test.go (99%) rename be1-go/{ => old}/channel/election/verification.go (100%) rename be1-go/{ => old}/channel/election/verification_test.go (100%) rename be1-go/{ => old}/channel/generalChirping/generalChirping.go (98%) rename be1-go/{ => old}/channel/generalChirping/generalChirping_test.go (99%) rename be1-go/{ => old}/channel/lao/lao.go (98%) rename be1-go/{ => old}/channel/lao/lao_test.go (99%) rename be1-go/{ => old}/channel/lao/verification.go (100%) rename be1-go/{ => old}/channel/lao/verification_test.go (98%) rename be1-go/{ => old}/channel/reaction/reaction.go (99%) rename be1-go/{ => old}/channel/reaction/reaction_test.go (99%) rename be1-go/{ => old}/channel/registry/registry.go (100%) rename be1-go/{ => old}/hub/hub.go (100%) rename be1-go/{ => old}/hub/standard_hub/hub_state/channels.go (93%) rename be1-go/{ => old}/hub/standard_hub/hub_state/messageIds.go (100%) rename be1-go/{ => old}/hub/standard_hub/hub_state/peers.go (100%) rename be1-go/{ => old}/hub/standard_hub/hub_state/queries.go (100%) rename be1-go/{ => old}/hub/standard_hub/hub_state/threadSafeMap.go (100%) rename be1-go/{ => old}/hub/standard_hub/hub_state/threadSafeSlice.go (100%) rename be1-go/{ => old}/hub/standard_hub/message_handling.go (99%) rename be1-go/{ => old}/hub/standard_hub/standard_hub.go (97%) rename be1-go/{ => old}/hub/standard_hub/standard_hub_test.go (99%) rename be1-go/{ => old}/inbox/hub_inbox.go (96%) rename be1-go/{ => old}/inbox/inbox.go (100%) rename be1-go/{ => old}/inbox/inbox_test.go (100%) rename be1-go/{channel/coin => }/uint53/uint53.go (100%) rename be1-go/{channel/coin => }/uint53/uint53_test.go (100%) diff --git a/be1-go/cli/cli.go b/be1-go/cli/cli.go index 4eef41c365..85e95a77e2 100644 --- a/be1-go/cli/cli.go +++ b/be1-go/cli/cli.go @@ -9,7 +9,6 @@ import ( "os" popstellar "popstellar" "popstellar/crypto" - "popstellar/hub" "popstellar/internal/popserver" "popstellar/internal/popserver/config" "popstellar/internal/popserver/database" @@ -18,6 +17,7 @@ import ( "popstellar/internal/popserver/utils" "popstellar/network" "popstellar/network/socket" + "popstellar/old/hub" "popstellar/validation" "sync" "time" diff --git a/be1-go/cli/cli_test.go b/be1-go/cli/cli_test.go index 52e5da7215..3854b6df03 100644 --- a/be1-go/cli/cli_test.go +++ b/be1-go/cli/cli_test.go @@ -6,11 +6,11 @@ import ( "golang.org/x/xerrors" "io" "os" - "popstellar/channel/lao" "popstellar/crypto" - "popstellar/hub/standard_hub" "popstellar/network" "popstellar/network/socket" + "popstellar/old/channel/lao" + "popstellar/old/hub/standard_hub" "sync" "testing" "time" diff --git a/be1-go/message/messagedata/coin_post_transaction.go b/be1-go/message/messagedata/coin_post_transaction.go index 0f40fac829..d304ab54ed 100644 --- a/be1-go/message/messagedata/coin_post_transaction.go +++ b/be1-go/message/messagedata/coin_post_transaction.go @@ -5,9 +5,9 @@ import ( "encoding/base64" "go.dedis.ch/kyber/v3/sign/schnorr" "golang.org/x/xerrors" - "popstellar/channel/coin/uint53" "popstellar/crypto" "popstellar/message/answer" + "popstellar/uint53" "strconv" ) diff --git a/be1-go/network/server.go b/be1-go/network/server.go index e7c3b6686d..a55f269c31 100644 --- a/be1-go/network/server.go +++ b/be1-go/network/server.go @@ -5,8 +5,8 @@ import ( "fmt" "net/http" "popstellar" - "popstellar/hub" "popstellar/network/socket" + "popstellar/old/hub" "sync" "time" diff --git a/be1-go/network/server_test.go b/be1-go/network/server_test.go index 9a3e732d8a..d6db745542 100644 --- a/be1-go/network/server_test.go +++ b/be1-go/network/server_test.go @@ -5,8 +5,8 @@ import ( "net/http" "net/http/httptest" "popstellar/crypto" - "popstellar/hub" - "popstellar/hub/standard_hub" + "popstellar/old/hub" + "popstellar/old/hub/standard_hub" "testing" "github.com/rs/zerolog" diff --git a/be1-go/channel/authentication/authentication.go b/be1-go/old/channel/authentication/authentication.go similarity index 99% rename from be1-go/channel/authentication/authentication.go rename to be1-go/old/channel/authentication/authentication.go index 3fe151290a..0f70c8fce4 100644 --- a/be1-go/channel/authentication/authentication.go +++ b/be1-go/old/channel/authentication/authentication.go @@ -9,15 +9,15 @@ import ( "golang.org/x/xerrors" "net/url" "os" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" "popstellar/message/answer" "popstellar/message/messagedata" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "strings" diff --git a/be1-go/channel/authentication/authentication_test.go b/be1-go/old/channel/authentication/authentication_test.go similarity index 96% rename from be1-go/channel/authentication/authentication_test.go rename to be1-go/old/channel/authentication/authentication_test.go index 7f8f711996..5768234bf2 100644 --- a/be1-go/channel/authentication/authentication_test.go +++ b/be1-go/old/channel/authentication/authentication_test.go @@ -19,12 +19,12 @@ import ( "os" "path/filepath" "popstellar" - "popstellar/channel" "popstellar/crypto" "popstellar/message/messagedata" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -32,10 +32,10 @@ import ( ) const ( - relativeMsgDataExamplePath string = "../../../protocol/examples/messageData" - relativeQueryExamplePath string = "../../../protocol/examples/query" - secPathTest = "../../crypto/popcha.rsa" - pubPathtest = "../../crypto/popcha.rsa.pub" + relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" + relativeQueryExamplePath string = "../../../../protocol/examples/query" + secPathTest = "../../../crypto/popcha.rsa" + pubPathtest = "../../../crypto/popcha.rsa.pub" ) // TestJWTToken creates a JWT token with arbitrary parameters, and parse it to assert its correctness. diff --git a/be1-go/channel/channel.go b/be1-go/old/channel/channel.go similarity index 100% rename from be1-go/channel/channel.go rename to be1-go/old/channel/channel.go diff --git a/be1-go/channel/chirp/chirp.go b/be1-go/old/channel/chirp/chirp.go similarity index 99% rename from be1-go/channel/chirp/chirp.go rename to be1-go/old/channel/chirp/chirp.go index 0f99581015..324c198289 100644 --- a/be1-go/channel/chirp/chirp.go +++ b/be1-go/old/channel/chirp/chirp.go @@ -3,10 +3,7 @@ package chirp import ( "encoding/base64" "encoding/json" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -14,6 +11,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "time" diff --git a/be1-go/channel/chirp/chirp_test.go b/be1-go/old/channel/chirp/chirp_test.go similarity index 98% rename from be1-go/channel/chirp/chirp_test.go rename to be1-go/old/channel/chirp/chirp_test.go index 667fc17c7a..5a5b1efe69 100644 --- a/be1-go/channel/chirp/chirp_test.go +++ b/be1-go/old/channel/chirp/chirp_test.go @@ -7,8 +7,6 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" - "popstellar/channel/generalChirping" "popstellar/crypto" jsonrpc "popstellar/message" "popstellar/message/messagedata" @@ -16,6 +14,8 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/generalChirping" "popstellar/validation" "sync" "testing" @@ -34,8 +34,8 @@ const ( sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" generalName = "/root/" + laoID + "/social/posts" chirpChannelName = "/root/" + laoID + "/social/" + sender - relativeMsgDataExamplePath string = "../../../protocol/examples/messageData" - relativeQueryExamplePath string = "../../../protocol/examples/query" + relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" + relativeQueryExamplePath string = "../../../../protocol/examples/query" ) // Tests that the channel works correctly when it receives a subscribe from a diff --git a/be1-go/channel/coin/coin.go b/be1-go/old/channel/coin/coin.go similarity index 98% rename from be1-go/channel/coin/coin.go rename to be1-go/old/channel/coin/coin.go index 08439afbf6..d5178232fd 100644 --- a/be1-go/channel/coin/coin.go +++ b/be1-go/old/channel/coin/coin.go @@ -5,9 +5,6 @@ import ( "encoding/json" "github.com/rs/zerolog" "golang.org/x/xerrors" - "popstellar/channel" - "popstellar/channel/registry" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -15,6 +12,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" ) diff --git a/be1-go/channel/coin/coin_test.go b/be1-go/old/channel/coin/coin_test.go similarity index 99% rename from be1-go/channel/coin/coin_test.go rename to be1-go/old/channel/coin/coin_test.go index 8f7ff8d5ae..8678c8d44e 100644 --- a/be1-go/channel/coin/coin_test.go +++ b/be1-go/old/channel/coin/coin_test.go @@ -7,12 +7,12 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" "popstellar/message/messagedata" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -26,7 +26,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../protocol" +const protocolRelativePath string = "../../../../protocol" // Tests that the channel works correctly when it receives a subscribe func Test_General_Channel_Subscribe(t *testing.T) { diff --git a/be1-go/channel/consensus/consensus.go b/be1-go/old/channel/consensus/consensus.go similarity index 99% rename from be1-go/channel/consensus/consensus.go rename to be1-go/old/channel/consensus/consensus.go index 9ab484afea..cc9d2d42c1 100644 --- a/be1-go/channel/consensus/consensus.go +++ b/be1-go/old/channel/consensus/consensus.go @@ -3,10 +3,7 @@ package consensus import ( "encoding/base64" "encoding/json" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -14,6 +11,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "sync" diff --git a/be1-go/channel/consensus/consensus_test.go b/be1-go/old/channel/consensus/consensus_test.go similarity index 99% rename from be1-go/channel/consensus/consensus_test.go rename to be1-go/old/channel/consensus/consensus_test.go index 75cc1e8a43..0b4286edca 100644 --- a/be1-go/channel/consensus/consensus_test.go +++ b/be1-go/old/channel/consensus/consensus_test.go @@ -7,7 +7,6 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" jsonrpc "popstellar/message" "popstellar/message/messagedata" @@ -15,6 +14,7 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -29,7 +29,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../protocol" +const protocolRelativePath string = "../../../../protocol" // Tests that the channel works correctly when it receives a subscribe from a // client diff --git a/be1-go/channel/consensus/message_creation.go b/be1-go/old/channel/consensus/message_creation.go similarity index 100% rename from be1-go/channel/consensus/message_creation.go rename to be1-go/old/channel/consensus/message_creation.go diff --git a/be1-go/channel/election/election.go b/be1-go/old/channel/election/election.go similarity index 99% rename from be1-go/channel/election/election.go rename to be1-go/old/channel/election/election.go index b00b29ec85..d6f9dc29af 100644 --- a/be1-go/channel/election/election.go +++ b/be1-go/old/channel/election/election.go @@ -5,10 +5,7 @@ import ( "encoding/base64" "encoding/binary" "encoding/json" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -16,6 +13,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "strings" diff --git a/be1-go/channel/election/election_test.go b/be1-go/old/channel/election/election_test.go similarity index 99% rename from be1-go/channel/election/election_test.go rename to be1-go/old/channel/election/election_test.go index 32263115b3..664eae1c64 100644 --- a/be1-go/channel/election/election_test.go +++ b/be1-go/old/channel/election/election_test.go @@ -8,12 +8,12 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" "popstellar/message/messagedata" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -29,8 +29,8 @@ import ( ) const ( - relativeQueryExamplePath string = "../../../protocol/examples/query" - relativeMsgDataExamplePath string = "../../../protocol/examples/messageData" + relativeQueryExamplePath string = "../../../../protocol/examples/query" + relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" ) // Tests that the channel creation fails if two questions are the same diff --git a/be1-go/channel/election/verification.go b/be1-go/old/channel/election/verification.go similarity index 100% rename from be1-go/channel/election/verification.go rename to be1-go/old/channel/election/verification.go diff --git a/be1-go/channel/election/verification_test.go b/be1-go/old/channel/election/verification_test.go similarity index 100% rename from be1-go/channel/election/verification_test.go rename to be1-go/old/channel/election/verification_test.go diff --git a/be1-go/channel/generalChirping/generalChirping.go b/be1-go/old/channel/generalChirping/generalChirping.go similarity index 98% rename from be1-go/channel/generalChirping/generalChirping.go rename to be1-go/old/channel/generalChirping/generalChirping.go index e47cf4e9da..5f370d0be0 100644 --- a/be1-go/channel/generalChirping/generalChirping.go +++ b/be1-go/old/channel/generalChirping/generalChirping.go @@ -3,10 +3,7 @@ package generalChirping import ( "encoding/base64" "encoding/json" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -14,6 +11,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" diff --git a/be1-go/channel/generalChirping/generalChirping_test.go b/be1-go/old/channel/generalChirping/generalChirping_test.go similarity index 99% rename from be1-go/channel/generalChirping/generalChirping_test.go rename to be1-go/old/channel/generalChirping/generalChirping_test.go index dfaacd7daf..e899924607 100644 --- a/be1-go/channel/generalChirping/generalChirping_test.go +++ b/be1-go/old/channel/generalChirping/generalChirping_test.go @@ -6,11 +6,11 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -24,7 +24,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../protocol" +const protocolRelativePath string = "../../../../protocol" // Tests that the channel works correctly when it receives a subscribe func Test_General_Channel_Subscribe(t *testing.T) { diff --git a/be1-go/channel/lao/lao.go b/be1-go/old/channel/lao/lao.go similarity index 98% rename from be1-go/channel/lao/lao.go rename to be1-go/old/channel/lao/lao.go index 35a13c475f..8c87c9fb33 100644 --- a/be1-go/channel/lao/lao.go +++ b/be1-go/old/channel/lao/lao.go @@ -5,17 +5,7 @@ import ( "encoding/json" "fmt" popstellar "popstellar" - "popstellar/channel" - "popstellar/channel/authentication" - "popstellar/channel/chirp" - "popstellar/channel/coin" - "popstellar/channel/consensus" - "popstellar/channel/election" - "popstellar/channel/generalChirping" - "popstellar/channel/reaction" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -23,6 +13,16 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/authentication" + "popstellar/old/channel/chirp" + "popstellar/old/channel/coin" + "popstellar/old/channel/consensus" + "popstellar/old/channel/election" + "popstellar/old/channel/generalChirping" + "popstellar/old/channel/reaction" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "strings" diff --git a/be1-go/channel/lao/lao_test.go b/be1-go/old/channel/lao/lao_test.go similarity index 99% rename from be1-go/channel/lao/lao_test.go rename to be1-go/old/channel/lao/lao_test.go index 6d5d37efff..b9ed1e0063 100644 --- a/be1-go/channel/lao/lao_test.go +++ b/be1-go/old/channel/lao/lao_test.go @@ -8,7 +8,6 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" jsonrpc "popstellar/message" "popstellar/message/messagedata" @@ -16,6 +15,7 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "strconv" "sync" @@ -30,7 +30,7 @@ import ( "github.com/stretchr/testify/require" ) -const protocolRelativePath string = "../../../protocol" +const protocolRelativePath string = "../../../../protocol" func TestLAOChannel_Subscribe(t *testing.T) { keypair := generateKeyPair(t) diff --git a/be1-go/channel/lao/verification.go b/be1-go/old/channel/lao/verification.go similarity index 100% rename from be1-go/channel/lao/verification.go rename to be1-go/old/channel/lao/verification.go diff --git a/be1-go/channel/lao/verification_test.go b/be1-go/old/channel/lao/verification_test.go similarity index 98% rename from be1-go/channel/lao/verification_test.go rename to be1-go/old/channel/lao/verification_test.go index e121382f03..851fef7204 100644 --- a/be1-go/channel/lao/verification_test.go +++ b/be1-go/old/channel/lao/verification_test.go @@ -4,9 +4,9 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/channel" "popstellar/message/messagedata" "popstellar/message/query/method/message" + "popstellar/old/channel" "testing" "github.com/stretchr/testify/require" @@ -15,7 +15,7 @@ import ( var relativeExamplePath string func init() { - relativeExamplePath = filepath.Join("..", "..", "..", "protocol", + relativeExamplePath = filepath.Join("..", "..", "..", "..", "protocol", "examples", "messageData") } diff --git a/be1-go/channel/reaction/reaction.go b/be1-go/old/channel/reaction/reaction.go similarity index 99% rename from be1-go/channel/reaction/reaction.go rename to be1-go/old/channel/reaction/reaction.go index e42e621cbd..791fb5e4e6 100644 --- a/be1-go/channel/reaction/reaction.go +++ b/be1-go/old/channel/reaction/reaction.go @@ -3,10 +3,7 @@ package reaction import ( "encoding/base64" "encoding/json" - "popstellar/channel" - "popstellar/channel/registry" "popstellar/crypto" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -14,6 +11,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/channel/registry" + "popstellar/old/inbox" "popstellar/validation" "strconv" "sync" diff --git a/be1-go/channel/reaction/reaction_test.go b/be1-go/old/channel/reaction/reaction_test.go similarity index 99% rename from be1-go/channel/reaction/reaction_test.go rename to be1-go/old/channel/reaction/reaction_test.go index ba953c0e8f..f13545a80d 100644 --- a/be1-go/channel/reaction/reaction_test.go +++ b/be1-go/old/channel/reaction/reaction_test.go @@ -7,7 +7,6 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" "popstellar/crypto" jsonrpc "popstellar/message" "popstellar/message/messagedata" @@ -15,6 +14,7 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "popstellar/validation" "sync" "testing" @@ -32,7 +32,7 @@ const ( laoID = "fzJSZjKf-2cbXH7kds9H8NORuuFIRLkevJlN7qQemjo=" sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" reactionChannelName = "/root/" + laoID + "/social/reactions" - protocolRelativePath string = "../../../protocol" + protocolRelativePath string = "../../../../protocol" ) // Tests that the channel works correctly when it receives a subscribe from a diff --git a/be1-go/channel/registry/registry.go b/be1-go/old/channel/registry/registry.go similarity index 100% rename from be1-go/channel/registry/registry.go rename to be1-go/old/channel/registry/registry.go diff --git a/be1-go/hub/hub.go b/be1-go/old/hub/hub.go similarity index 100% rename from be1-go/hub/hub.go rename to be1-go/old/hub/hub.go diff --git a/be1-go/hub/standard_hub/hub_state/channels.go b/be1-go/old/hub/standard_hub/hub_state/channels.go similarity index 93% rename from be1-go/hub/standard_hub/hub_state/channels.go rename to be1-go/old/hub/standard_hub/hub_state/channels.go index 29c3a0c95d..5aa0b7470f 100644 --- a/be1-go/hub/standard_hub/hub_state/channels.go +++ b/be1-go/old/hub/standard_hub/hub_state/channels.go @@ -1,6 +1,8 @@ package hub_state -import "popstellar/channel" +import ( + "popstellar/old/channel" +) // Channels stores channel ids with their corresponding channels type Channels struct { diff --git a/be1-go/hub/standard_hub/hub_state/messageIds.go b/be1-go/old/hub/standard_hub/hub_state/messageIds.go similarity index 100% rename from be1-go/hub/standard_hub/hub_state/messageIds.go rename to be1-go/old/hub/standard_hub/hub_state/messageIds.go diff --git a/be1-go/hub/standard_hub/hub_state/peers.go b/be1-go/old/hub/standard_hub/hub_state/peers.go similarity index 100% rename from be1-go/hub/standard_hub/hub_state/peers.go rename to be1-go/old/hub/standard_hub/hub_state/peers.go diff --git a/be1-go/hub/standard_hub/hub_state/queries.go b/be1-go/old/hub/standard_hub/hub_state/queries.go similarity index 100% rename from be1-go/hub/standard_hub/hub_state/queries.go rename to be1-go/old/hub/standard_hub/hub_state/queries.go diff --git a/be1-go/hub/standard_hub/hub_state/threadSafeMap.go b/be1-go/old/hub/standard_hub/hub_state/threadSafeMap.go similarity index 100% rename from be1-go/hub/standard_hub/hub_state/threadSafeMap.go rename to be1-go/old/hub/standard_hub/hub_state/threadSafeMap.go diff --git a/be1-go/hub/standard_hub/hub_state/threadSafeSlice.go b/be1-go/old/hub/standard_hub/hub_state/threadSafeSlice.go similarity index 100% rename from be1-go/hub/standard_hub/hub_state/threadSafeSlice.go rename to be1-go/old/hub/standard_hub/hub_state/threadSafeSlice.go diff --git a/be1-go/hub/standard_hub/message_handling.go b/be1-go/old/hub/standard_hub/message_handling.go similarity index 99% rename from be1-go/hub/standard_hub/message_handling.go rename to be1-go/old/hub/standard_hub/message_handling.go index 4fa849c21a..d2238d0d1b 100644 --- a/be1-go/hub/standard_hub/message_handling.go +++ b/be1-go/old/hub/standard_hub/message_handling.go @@ -4,7 +4,6 @@ import ( "encoding/base64" "encoding/json" "popstellar/crypto" - "popstellar/hub/standard_hub/hub_state" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -12,6 +11,7 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/hub/standard_hub/hub_state" "popstellar/validation" "github.com/rs/zerolog/log" diff --git a/be1-go/hub/standard_hub/standard_hub.go b/be1-go/old/hub/standard_hub/standard_hub.go similarity index 97% rename from be1-go/hub/standard_hub/standard_hub.go rename to be1-go/old/hub/standard_hub/standard_hub.go index 70ac150110..d66e2dbbaf 100644 --- a/be1-go/hub/standard_hub/standard_hub.go +++ b/be1-go/old/hub/standard_hub/standard_hub.go @@ -4,10 +4,7 @@ import ( "context" "encoding/base64" "encoding/json" - "popstellar/channel" "popstellar/crypto" - state "popstellar/hub/standard_hub/hub_state" - "popstellar/inbox" jsonrpc "popstellar/message" "popstellar/message/answer" "popstellar/message/messagedata" @@ -15,6 +12,9 @@ import ( "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" + "popstellar/old/hub/standard_hub/hub_state" + "popstellar/old/inbox" "popstellar/validation" "strings" "sync" @@ -58,7 +58,7 @@ type Hub struct { messageChan chan socket.IncomingMessage sync.RWMutex - channelByID state.Channels + channelByID hub_state.Channels closedSockets chan string @@ -83,16 +83,16 @@ type Hub struct { hubInbox inbox.HubInbox // queries are used to help servers catchup to each other - queries state.Queries + queries hub_state.Queries // peers stores information about the peers - peers state.Peers + peers hub_state.Peers // blacklist stores the IDs of the messages that failed to be processed by the hub // the server will not ask for them again in the heartbeat // and will not process them if they are received again // @TODO remove the messages from the blacklist after a certain amount of time by trying to process them again - blacklist state.ThreadSafeSlice[string] + blacklist hub_state.ThreadSafeSlice[string] } // NewHub returns a new Hub. @@ -112,7 +112,7 @@ func NewHub(pubKeyOwner kyber.Point, clientServerAddress string, serverServerAdd clientServerAddress: clientServerAddress, serverServerAddress: serverServerAddress, messageChan: make(chan socket.IncomingMessage), - channelByID: state.NewChannelsMap(), + channelByID: hub_state.NewChannelsMap(), closedSockets: make(chan string), pubKeyOwner: pubKeyOwner, pubKeyServ: pubServ, @@ -124,9 +124,9 @@ func NewHub(pubKeyOwner kyber.Point, clientServerAddress string, serverServerAdd laoFac: laoFac, serverSockets: channel.NewSockets(), hubInbox: *inbox.NewHubInbox(rootChannel), - queries: state.NewQueries(log), - peers: state.NewPeers(), - blacklist: state.NewThreadSafeSlice[string](), + queries: hub_state.NewQueries(log), + peers: hub_state.NewPeers(), + blacklist: hub_state.NewThreadSafeSlice[string](), } return &hub, nil diff --git a/be1-go/hub/standard_hub/standard_hub_test.go b/be1-go/old/hub/standard_hub/standard_hub_test.go similarity index 99% rename from be1-go/hub/standard_hub/standard_hub_test.go rename to be1-go/old/hub/standard_hub/standard_hub_test.go index d491d8a44b..02ed7bc69a 100644 --- a/be1-go/hub/standard_hub/standard_hub_test.go +++ b/be1-go/old/hub/standard_hub/standard_hub_test.go @@ -8,13 +8,13 @@ import ( "io" "os" "path/filepath" - "popstellar/channel" jsonrpc "popstellar/message" "popstellar/message/messagedata" "popstellar/message/query" "popstellar/message/query/method" "popstellar/message/query/method/message" "popstellar/network/socket" + "popstellar/old/channel" "sync" "testing" "time" @@ -846,7 +846,7 @@ func Test_Handle_Answer(t *testing.T) { ID: 1, Result: make([]message.Message, 1), } - messageDataPath := filepath.Join("..", "..", "..", "protocol", + messageDataPath := filepath.Join("..", "..", "..", "..", "protocol", "examples", "messageData", "lao_create", "lao_create.json") messageDataBuf, err := os.ReadFile(messageDataPath) diff --git a/be1-go/inbox/hub_inbox.go b/be1-go/old/inbox/hub_inbox.go similarity index 96% rename from be1-go/inbox/hub_inbox.go rename to be1-go/old/inbox/hub_inbox.go index 568641cb71..d977caa91b 100644 --- a/be1-go/inbox/hub_inbox.go +++ b/be1-go/old/inbox/hub_inbox.go @@ -1,8 +1,8 @@ package inbox import ( - state "popstellar/hub/standard_hub/hub_state" "popstellar/message/query/method/message" + state "popstellar/old/hub/standard_hub/hub_state" "sync" ) diff --git a/be1-go/inbox/inbox.go b/be1-go/old/inbox/inbox.go similarity index 100% rename from be1-go/inbox/inbox.go rename to be1-go/old/inbox/inbox.go diff --git a/be1-go/inbox/inbox_test.go b/be1-go/old/inbox/inbox_test.go similarity index 100% rename from be1-go/inbox/inbox_test.go rename to be1-go/old/inbox/inbox_test.go diff --git a/be1-go/popcha/server.go b/be1-go/popcha/server.go index 0df8ce67bb..9d6cb0f083 100644 --- a/be1-go/popcha/server.go +++ b/be1-go/popcha/server.go @@ -17,7 +17,7 @@ import ( "html/template" "io/fs" "net/http" - "popstellar/hub" + "popstellar/old/hub" "strconv" "strings" "sync" diff --git a/be1-go/popcha/server_test.go b/be1-go/popcha/server_test.go index d2bbee48ff..0c0d03966f 100644 --- a/be1-go/popcha/server_test.go +++ b/be1-go/popcha/server_test.go @@ -11,8 +11,8 @@ import ( "os" "popstellar" "popstellar/crypto" - "popstellar/hub" - "popstellar/hub/standard_hub" + "popstellar/old/hub" + "popstellar/old/hub/standard_hub" "reflect" "strings" "testing" diff --git a/be1-go/channel/coin/uint53/uint53.go b/be1-go/uint53/uint53.go similarity index 100% rename from be1-go/channel/coin/uint53/uint53.go rename to be1-go/uint53/uint53.go diff --git a/be1-go/channel/coin/uint53/uint53_test.go b/be1-go/uint53/uint53_test.go similarity index 100% rename from be1-go/channel/coin/uint53/uint53_test.go rename to be1-go/uint53/uint53_test.go From 5ec146b36484fc7008e8e9e5a57fdc99aafbd291 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 14:10:34 +0200 Subject: [PATCH 02/19] move everything inside internal --- be1-go/Makefile | 4 +- be1-go/cli/cli.go | 38 +++--- be1-go/cli/cli_test.go | 10 +- be1-go/{ => internal}/crypto/README.md | 0 be1-go/{ => internal}/crypto/popcha.rsa | 0 be1-go/{ => internal}/crypto/popcha.rsa.pub | 0 be1-go/{ => internal}/crypto/suite.go | 0 be1-go/internal/{ => docs}/depgraph/README.md | 0 be1-go/internal/{ => docs}/depgraph/dep.yml | 0 .../internal/{ => docs}/depgraph/depgraph.go | 0 .../{popserver => }/handler/answer.go | 28 ++-- .../{popserver => }/handler/answer_test.go | 10 +- .../{popserver => }/handler/channel.go | 26 ++-- .../{popserver => }/handler/channel_test.go | 10 +- .../internal/{popserver => }/handler/chirp.go | 10 +- .../{popserver => }/handler/chirp_test.go | 34 ++--- .../internal/{popserver => }/handler/coin.go | 8 +- .../{popserver => }/handler/coin_test.go | 34 ++--- .../{popserver => }/handler/election.go | 14 +- .../{popserver => }/handler/election_test.go | 44 +++---- .../{popserver => }/handler/federation.go | 42 +++--- .../handler/federation_test.go | 73 ++++++----- .../handler/incoming_message.go | 10 +- .../handler/incoming_message_test.go | 14 +- .../internal/{popserver => }/handler/lao.go | 14 +- .../{popserver => }/handler/lao_test.go | 26 ++-- .../{popserver => }/handler/publish.go | 22 ++-- .../internal/{popserver => }/handler/query.go | 30 ++--- .../{popserver => }/handler/query_test.go | 120 +++++++++--------- .../{popserver => }/handler/reaction.go | 8 +- .../{popserver => }/handler/reaction_test.go | 30 ++--- .../internal/{popserver => }/handler/root.go | 20 +-- .../{popserver => }/handler/root_test.go | 32 ++--- .../internal/{popserver => }/handler/rumor.go | 36 +++--- be1-go/internal/{popserver => hub}/hub.go | 70 +++++----- be1-go/{ => internal/logger}/logger.go | 2 +- .../{ => internal}/message/answer/answer.go | 2 +- be1-go/{ => internal}/message/answer/error.go | 0 be1-go/{ => internal}/message/jsonRPC.go | 0 .../message/messagedata/authenticate_user.go | 2 +- .../message/messagedata/chirp_add.go | 0 .../message/messagedata/chirp_broadcast.go | 0 .../message/messagedata/chirp_delete.go | 0 .../message/messagedata/chirp_notify_add.go | 0 .../messagedata/chirp_notify_delete.go | 0 .../messagedata/coin_post_transaction.go | 6 +- .../message/messagedata/consensus_accept.go | 0 .../message/messagedata/consensus_elect.go | 0 .../messagedata/consensus_elect_accept.go | 0 .../message/messagedata/consensus_failure.go | 0 .../message/messagedata/consensus_learn.go | 0 .../message/messagedata/consensus_prepare.go | 0 .../message/messagedata/consensus_promise.go | 0 .../message/messagedata/consensus_propose.go | 0 .../message/messagedata/election_end.go | 2 +- .../message/messagedata/election_key.go | 0 .../message/messagedata/election_open.go | 2 +- .../message/messagedata/election_result.go | 0 .../message/messagedata/election_setup.go | 2 +- .../messagedata/federation_challenge.go | 2 +- .../message/messagedata/federation_expect.go | 2 +- .../message/messagedata/federation_init.go | 2 +- .../federation_request_challenge.go | 0 .../message/messagedata/federation_result.go | 2 +- .../message/messagedata/lao_create.go | 2 +- .../message/messagedata/lao_greet.go | 0 .../message/messagedata/lao_state.go | 0 .../message/messagedata/lao_update.go | 0 .../message/messagedata/meeting_create.go | 0 .../message/messagedata/meeting_state.go | 0 .../message/messagedata/message_witness.go | 0 .../{ => internal}/message/messagedata/mod.go | 0 .../message/messagedata/reaction_add.go | 0 .../message/messagedata/reaction_delete.go | 0 .../message/messagedata/roll_call_close.go | 2 +- .../message/messagedata/roll_call_create.go | 2 +- .../message/messagedata/roll_call_open.go | 2 +- .../message/messagedata/roll_call_reopen.go | 0 .../message/messagedata/vote_cast_vote.go | 2 +- .../message/messagedata/vote_cast_write_in.go | 0 .../message/query/method/broadcast.go | 4 +- .../message/query/method/catchup.go | 2 +- .../query/method/get_messages_by_id.go | 2 +- .../message/query/method/greet_server.go | 2 +- .../message/query/method/heartbeat.go | 2 +- .../message/query/method/message/message.go | 2 +- .../message/query/method/publish.go | 4 +- .../message/query/method/rumor.go | 4 +- .../message/query/method/subscribe.go | 2 +- .../message/query/method/unsubscribe.go | 2 +- be1-go/{ => internal}/message/query/query.go | 2 +- .../message/test/answer/answer_test.go | 4 +- .../message/test/answer/error_test.go | 2 +- .../{ => internal}/message/test/answer/mod.go | 2 +- .../message/test/message_test.go | 6 +- .../messagedata/authenticate_user_test.go | 2 +- .../test/messagedata/chirp_add_test.go | 2 +- .../test/messagedata/chirp_broadcast_test.go | 2 +- .../test/messagedata/chirp_delete_test.go | 2 +- .../test/messagedata/chirp_notify_add_test.go | 2 +- .../messagedata/chirp_notify_delete_test.go | 2 +- .../messagedata/coin_post_transaction_test.go | 2 +- .../test/messagedata/consensus_accept_test.go | 2 +- .../consensus_elect_accept_test.go | 2 +- .../test/messagedata/consensus_elect_test.go | 2 +- .../messagedata/consensus_failure_test.go | 2 +- .../test/messagedata/consensus_learn_test.go | 2 +- .../messagedata/consensus_prepare_test.go | 2 +- .../messagedata/consensus_promise_test.go | 2 +- .../messagedata/consensus_propose_test.go | 2 +- .../test/messagedata/election_end_test.go | 2 +- .../test/messagedata/election_key_test.go | 2 +- .../test/messagedata/election_open_test.go | 2 +- .../test/messagedata/election_result_test.go | 2 +- .../test/messagedata/election_setup_test.go | 2 +- .../test/messagedata/lao_create_test.go | 2 +- .../test/messagedata/lao_greet_test.go | 2 +- .../test/messagedata/lao_state_test.go | 2 +- .../test/messagedata/lao_update_test.go | 2 +- .../test/messagedata/meeting_create_test.go | 2 +- .../test/messagedata/meeting_state_test.go | 2 +- .../test/messagedata/message_witness_test.go | 2 +- .../message/test/messagedata/mod_test.go | 4 +- .../test/messagedata/reaction_add_test.go | 2 +- .../test/messagedata/reaction_delete_test.go | 2 +- .../test/messagedata/roll_call_close_test.go | 2 +- .../test/messagedata/roll_call_create_test.go | 2 +- .../test/messagedata/roll_call_open_test.go | 2 +- .../test/messagedata/roll_call_reopen_test.go | 2 +- .../test/messagedata/vote_cast_vote_test.go | 2 +- be1-go/{ => internal}/message/test/mod.go | 0 .../test/query/method/broadcast_test.go | 4 +- .../message/test/query/method/catchup_test.go | 4 +- .../query/method/get_messages_by_id_test.go | 4 +- .../test/query/method/greet_server_test.go | 4 +- .../test/query/method/heartbeat_test.go | 4 +- .../message/test/query/method/mod.go | 2 +- .../message/test/query/method/publish_test.go | 4 +- .../test/query/method/subscribe_test.go | 4 +- .../test/query/method/unsubscribe_test.go | 4 +- be1-go/{ => internal}/network/network.go | 0 be1-go/{ => internal}/network/server.go | 10 +- be1-go/{ => internal}/network/server_test.go | 6 +- be1-go/{ => internal}/network/shutdown.go | 2 +- .../network/socket/fake_socket.go | 2 +- .../{ => internal}/network/socket/socket.go | 2 +- .../network/socket/socket_impl.go | 6 +- .../network/socket/socket_impl_test.go | 4 +- .../channel/authentication/authentication.go | 20 +-- .../authentication/authentication_test.go | 22 ++-- be1-go/{ => internal}/old/channel/channel.go | 8 +- .../{ => internal}/old/channel/chirp/chirp.go | 24 ++-- .../old/channel/chirp/chirp_test.go | 24 ++-- .../{ => internal}/old/channel/coin/coin.go | 22 ++-- .../old/channel/coin/coin_test.go | 16 +-- .../old/channel/consensus/consensus.go | 24 ++-- .../old/channel/consensus/consensus_test.go | 20 +-- .../old/channel/consensus/message_creation.go | 2 +- .../old/channel/election/election.go | 24 ++-- .../old/channel/election/election_test.go | 18 +-- .../old/channel/election/verification.go | 4 +- .../old/channel/election/verification_test.go | 4 +- .../generalChirping/generalChirping.go | 24 ++-- .../generalChirping/generalChirping_test.go | 14 +- be1-go/{ => internal}/old/channel/lao/lao.go | 40 +++--- .../old/channel/lao/lao_test.go | 20 +-- .../old/channel/lao/verification.go | 2 +- .../old/channel/lao/verification_test.go | 8 +- .../old/channel/reaction/reaction.go | 24 ++-- .../old/channel/reaction/reaction_test.go | 20 +-- .../old/channel/registry/registry.go | 6 +- be1-go/{ => internal}/old/hub/hub.go | 2 +- .../hub/standard_hub/hub_state/channels.go | 2 +- .../hub/standard_hub/hub_state/messageIds.go | 0 .../old/hub/standard_hub/hub_state/peers.go | 4 +- .../old/hub/standard_hub/hub_state/queries.go | 2 +- .../standard_hub/hub_state/threadSafeMap.go | 0 .../standard_hub/hub_state/threadSafeSlice.go | 0 .../old/hub/standard_hub/message_handling.go | 20 +-- .../old/hub/standard_hub/standard_hub.go | 24 ++-- .../old/hub/standard_hub/standard_hub_test.go | 16 +-- be1-go/{ => internal}/old/inbox/hub_inbox.go | 4 +- be1-go/{ => internal}/old/inbox/inbox.go | 2 +- be1-go/{ => internal}/old/inbox/inbox_test.go | 2 +- be1-go/{ => internal}/popcha/docs/README.md | 0 .../{ => internal}/popcha/qrcode/popcha.html | 0 be1-go/{ => internal}/popcha/server.go | 2 +- be1-go/{ => internal}/popcha/server_test.go | 14 +- .../internal/popserver/database/database.go | 71 ----------- .../repository/mock_repository.go | 9 +- .../database => }/repository/repository.go | 8 +- .../{popserver => singleton}/config/config.go | 2 +- .../internal/singleton/database/database.go | 71 +++++++++++ .../state/hub_parameter.go | 4 +- .../{popserver => singleton}/state/peerer.go | 4 +- .../{popserver => singleton}/state/querier.go | 4 +- .../state/socketer.go | 4 +- .../{popserver => singleton}/state/state.go | 14 +- .../state/subscriber.go | 4 +- .../{popserver => singleton}/utils/utils.go | 4 +- .../{popserver/database => }/sqlite/sqlite.go | 14 +- .../database => }/sqlite/sqlite_const.go | 0 .../database => }/sqlite/sqlite_init.go | 2 +- .../database => }/sqlite/sqlite_test.go | 74 +++++------ .../generatortest/chirp.go | 4 +- .../generatortest/election.go | 4 +- .../generatortest/federation.go | 4 +- .../generatortest/generatortest.go | 6 +- .../{popserver => test}/generatortest/lao.go | 4 +- .../generatortest/query.go | 8 +- .../generatortest/reaction.go | 4 +- .../{popserver => test}/generatortest/root.go | 4 +- .../{popserver => }/types/hub_params.go | 2 +- .../internal/{popserver => }/types/peers.go | 4 +- .../internal/{popserver => }/types/queries.go | 2 +- .../{popserver => }/types/question.go | 0 .../internal/{popserver => }/types/sockets.go | 6 +- .../{popserver => }/types/subscribers.go | 4 +- be1-go/{ => internal/types}/uint53/uint53.go | 0 .../types}/uint53/uint53_test.go | 0 .../validation/schema_validator.go | 2 +- .../validation/schema_validator_test.go | 0 .../{ => internal}/validation/validation.go | 0 223 files changed, 931 insertions(+), 933 deletions(-) rename be1-go/{ => internal}/crypto/README.md (100%) rename be1-go/{ => internal}/crypto/popcha.rsa (100%) rename be1-go/{ => internal}/crypto/popcha.rsa.pub (100%) rename be1-go/{ => internal}/crypto/suite.go (100%) rename be1-go/internal/{ => docs}/depgraph/README.md (100%) rename be1-go/internal/{ => docs}/depgraph/dep.yml (100%) rename be1-go/internal/{ => docs}/depgraph/depgraph.go (100%) rename be1-go/internal/{popserver => }/handler/answer.go (81%) rename be1-go/internal/{popserver => }/handler/answer_test.go (93%) rename be1-go/internal/{popserver => }/handler/channel.go (91%) rename be1-go/internal/{popserver => }/handler/channel_test.go (96%) rename be1-go/internal/{popserver => }/handler/chirp.go (96%) rename be1-go/internal/{popserver => }/handler/chirp_test.go (86%) rename be1-go/internal/{popserver => }/handler/coin.go (89%) rename be1-go/internal/{popserver => }/handler/coin_test.go (86%) rename be1-go/internal/{popserver => }/handler/election.go (98%) rename be1-go/internal/{popserver => }/handler/election_test.go (95%) rename be1-go/internal/{popserver => }/handler/federation.go (94%) rename be1-go/internal/{popserver => }/handler/federation_test.go (94%) rename be1-go/internal/{popserver => }/handler/incoming_message.go (82%) rename be1-go/internal/{popserver => }/handler/incoming_message_test.go (75%) rename be1-go/internal/{popserver => }/handler/lao.go (98%) rename be1-go/internal/{popserver => }/handler/lao_test.go (96%) rename be1-go/internal/{popserver => }/handler/publish.go (65%) rename be1-go/internal/{popserver => }/handler/query.go (90%) rename be1-go/internal/{popserver => }/handler/query_test.go (82%) rename be1-go/internal/{popserver => }/handler/reaction.go (94%) rename be1-go/internal/{popserver => }/handler/reaction_test.go (92%) rename be1-go/internal/{popserver => }/handler/root.go (94%) rename be1-go/internal/{popserver => }/handler/root_test.go (84%) rename be1-go/internal/{popserver => }/handler/rumor.go (80%) rename be1-go/internal/{popserver => hub}/hub.go (71%) rename be1-go/{ => internal/logger}/logger.go (98%) rename be1-go/{ => internal}/message/answer/answer.go (97%) rename be1-go/{ => internal}/message/answer/error.go (100%) rename be1-go/{ => internal}/message/jsonRPC.go (100%) rename be1-go/{ => internal}/message/messagedata/authenticate_user.go (98%) rename be1-go/{ => internal}/message/messagedata/chirp_add.go (100%) rename be1-go/{ => internal}/message/messagedata/chirp_broadcast.go (100%) rename be1-go/{ => internal}/message/messagedata/chirp_delete.go (100%) rename be1-go/{ => internal}/message/messagedata/chirp_notify_add.go (100%) rename be1-go/{ => internal}/message/messagedata/chirp_notify_delete.go (100%) rename be1-go/{ => internal}/message/messagedata/coin_post_transaction.go (98%) rename be1-go/{ => internal}/message/messagedata/consensus_accept.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_elect.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_elect_accept.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_failure.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_learn.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_prepare.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_promise.go (100%) rename be1-go/{ => internal}/message/messagedata/consensus_propose.go (100%) rename be1-go/{ => internal}/message/messagedata/election_end.go (98%) rename be1-go/{ => internal}/message/messagedata/election_key.go (100%) rename be1-go/{ => internal}/message/messagedata/election_open.go (98%) rename be1-go/{ => internal}/message/messagedata/election_result.go (100%) rename be1-go/{ => internal}/message/messagedata/election_setup.go (99%) rename be1-go/{ => internal}/message/messagedata/federation_challenge.go (97%) rename be1-go/{ => internal}/message/messagedata/federation_expect.go (92%) rename be1-go/{ => internal}/message/messagedata/federation_init.go (92%) rename be1-go/{ => internal}/message/messagedata/federation_request_challenge.go (100%) rename be1-go/{ => internal}/message/messagedata/federation_result.go (92%) rename be1-go/{ => internal}/message/messagedata/lao_create.go (98%) rename be1-go/{ => internal}/message/messagedata/lao_greet.go (100%) rename be1-go/{ => internal}/message/messagedata/lao_state.go (100%) rename be1-go/{ => internal}/message/messagedata/lao_update.go (100%) rename be1-go/{ => internal}/message/messagedata/meeting_create.go (100%) rename be1-go/{ => internal}/message/messagedata/meeting_state.go (100%) rename be1-go/{ => internal}/message/messagedata/message_witness.go (100%) rename be1-go/{ => internal}/message/messagedata/mod.go (100%) rename be1-go/{ => internal}/message/messagedata/reaction_add.go (100%) rename be1-go/{ => internal}/message/messagedata/reaction_delete.go (100%) rename be1-go/{ => internal}/message/messagedata/roll_call_close.go (97%) rename be1-go/{ => internal}/message/messagedata/roll_call_create.go (98%) rename be1-go/{ => internal}/message/messagedata/roll_call_open.go (97%) rename be1-go/{ => internal}/message/messagedata/roll_call_reopen.go (100%) rename be1-go/{ => internal}/message/messagedata/vote_cast_vote.go (98%) rename be1-go/{ => internal}/message/messagedata/vote_cast_write_in.go (100%) rename be1-go/{ => internal}/message/query/method/broadcast.go (75%) rename be1-go/{ => internal}/message/query/method/catchup.go (83%) rename be1-go/{ => internal}/message/query/method/get_messages_by_id.go (84%) rename be1-go/{ => internal}/message/query/method/greet_server.go (88%) rename be1-go/{ => internal}/message/query/method/heartbeat.go (81%) rename be1-go/{ => internal}/message/query/method/message/message.go (98%) rename be1-go/{ => internal}/message/query/method/publish.go (76%) rename be1-go/{ => internal}/message/query/method/rumor.go (80%) rename be1-go/{ => internal}/message/query/method/subscribe.go (84%) rename be1-go/{ => internal}/message/query/method/unsubscribe.go (84%) rename be1-go/{ => internal}/message/query/query.go (91%) rename be1-go/{ => internal}/message/test/answer/answer_test.go (96%) rename be1-go/{ => internal}/message/test/answer/error_test.go (87%) rename be1-go/{ => internal}/message/test/answer/mod.go (58%) rename be1-go/{ => internal}/message/test/message_test.go (87%) rename be1-go/{ => internal}/message/test/messagedata/authenticate_user_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/chirp_add_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/chirp_broadcast_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/chirp_delete_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/chirp_notify_add_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/chirp_notify_delete_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/coin_post_transaction_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_accept_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_elect_accept_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_elect_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_failure_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_learn_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_prepare_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_promise_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/consensus_propose_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/election_end_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/election_key_test.go (95%) rename be1-go/{ => internal}/message/test/messagedata/election_open_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/election_result_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/election_setup_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/lao_create_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/lao_greet_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/lao_state_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/lao_update_test.go (98%) rename be1-go/{ => internal}/message/test/messagedata/meeting_create_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/meeting_state_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/message_witness_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/mod_test.go (94%) rename be1-go/{ => internal}/message/test/messagedata/reaction_add_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/reaction_delete_test.go (97%) rename be1-go/{ => internal}/message/test/messagedata/roll_call_close_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/roll_call_create_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/roll_call_open_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/roll_call_reopen_test.go (96%) rename be1-go/{ => internal}/message/test/messagedata/vote_cast_vote_test.go (97%) rename be1-go/{ => internal}/message/test/mod.go (100%) rename be1-go/{ => internal}/message/test/query/method/broadcast_test.go (91%) rename be1-go/{ => internal}/message/test/query/method/catchup_test.go (91%) rename be1-go/{ => internal}/message/test/query/method/get_messages_by_id_test.go (95%) rename be1-go/{ => internal}/message/test/query/method/greet_server_test.go (93%) rename be1-go/{ => internal}/message/test/query/method/heartbeat_test.go (94%) rename be1-go/{ => internal}/message/test/query/method/mod.go (89%) rename be1-go/{ => internal}/message/test/query/method/publish_test.go (95%) rename be1-go/{ => internal}/message/test/query/method/subscribe_test.go (91%) rename be1-go/{ => internal}/message/test/query/method/unsubscribe_test.go (91%) rename be1-go/{ => internal}/network/network.go (100%) rename be1-go/{ => internal}/network/server.go (96%) rename be1-go/{ => internal}/network/server_test.go (90%) rename be1-go/{ => internal}/network/shutdown.go (96%) rename be1-go/{ => internal}/network/socket/fake_socket.go (93%) rename be1-go/{ => internal}/network/socket/socket.go (97%) rename be1-go/{ => internal}/network/socket/socket_impl.go (98%) rename be1-go/{ => internal}/network/socket/socket_impl_test.go (96%) rename be1-go/{ => internal}/old/channel/authentication/authentication.go (97%) rename be1-go/{ => internal}/old/channel/authentication/authentication_test.go (94%) rename be1-go/{ => internal}/old/channel/channel.go (94%) rename be1-go/{ => internal}/old/channel/chirp/chirp.go (95%) rename be1-go/{ => internal}/old/channel/chirp/chirp_test.go (97%) rename be1-go/{ => internal}/old/channel/coin/coin.go (92%) rename be1-go/{ => internal}/old/channel/coin/coin_test.go (98%) rename be1-go/{ => internal}/old/channel/consensus/consensus.go (98%) rename be1-go/{ => internal}/old/channel/consensus/consensus_test.go (99%) rename be1-go/{ => internal}/old/channel/consensus/message_creation.go (99%) rename be1-go/{ => internal}/old/channel/election/election.go (97%) rename be1-go/{ => internal}/old/channel/election/election_test.go (98%) rename be1-go/{ => internal}/old/channel/election/verification.go (99%) rename be1-go/{ => internal}/old/channel/election/verification_test.go (99%) rename be1-go/{ => internal}/old/channel/generalChirping/generalChirping.go (93%) rename be1-go/{ => internal}/old/channel/generalChirping/generalChirping_test.go (96%) rename be1-go/{ => internal}/old/channel/lao/lao.go (96%) rename be1-go/{ => internal}/old/channel/lao/lao_test.go (98%) rename be1-go/{ => internal}/old/channel/lao/verification.go (99%) rename be1-go/{ => internal}/old/channel/lao/verification_test.go (97%) rename be1-go/{ => internal}/old/channel/reaction/reaction.go (94%) rename be1-go/{ => internal}/old/channel/reaction/reaction_test.go (97%) rename be1-go/{ => internal}/old/channel/registry/registry.go (94%) rename be1-go/{ => internal}/old/hub/hub.go (96%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/channels.go (93%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/messageIds.go (100%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/peers.go (95%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/queries.go (97%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/threadSafeMap.go (100%) rename be1-go/{ => internal}/old/hub/standard_hub/hub_state/threadSafeSlice.go (100%) rename be1-go/{ => internal}/old/hub/standard_hub/message_handling.go (97%) rename be1-go/{ => internal}/old/hub/standard_hub/standard_hub.go (97%) rename be1-go/{ => internal}/old/hub/standard_hub/standard_hub_test.go (99%) rename be1-go/{ => internal}/old/inbox/hub_inbox.go (93%) rename be1-go/{ => internal}/old/inbox/inbox.go (98%) rename be1-go/{ => internal}/old/inbox/inbox_test.go (98%) rename be1-go/{ => internal}/popcha/docs/README.md (100%) rename be1-go/{ => internal}/popcha/qrcode/popcha.html (100%) rename be1-go/{ => internal}/popcha/server.go (99%) rename be1-go/{ => internal}/popcha/server_test.go (98%) delete mode 100644 be1-go/internal/popserver/database/database.go rename be1-go/internal/{popserver/database => }/repository/mock_repository.go (99%) rename be1-go/internal/{popserver/database => }/repository/repository.go (98%) rename be1-go/internal/{popserver => singleton}/config/config.go (98%) create mode 100644 be1-go/internal/singleton/database/database.go rename be1-go/internal/{popserver => singleton}/state/hub_parameter.go (93%) rename be1-go/internal/{popserver => singleton}/state/peerer.go (94%) rename be1-go/internal/{popserver => singleton}/state/querier.go (95%) rename be1-go/internal/{popserver => singleton}/state/socketer.go (94%) rename be1-go/internal/{popserver => singleton}/state/state.go (81%) rename be1-go/internal/{popserver => singleton}/state/subscriber.go (95%) rename be1-go/internal/{popserver => singleton}/utils/utils.go (93%) rename be1-go/internal/{popserver/database => }/sqlite/sqlite.go (99%) rename be1-go/internal/{popserver/database => }/sqlite/sqlite_const.go (100%) rename be1-go/internal/{popserver/database => }/sqlite/sqlite_init.go (98%) rename be1-go/internal/{popserver/database => }/sqlite/sqlite_test.go (89%) rename be1-go/internal/{popserver => test}/generatortest/chirp.go (91%) rename be1-go/internal/{popserver => test}/generatortest/election.go (97%) rename be1-go/internal/{popserver => test}/generatortest/federation.go (97%) rename be1-go/internal/{popserver => test}/generatortest/generatortest.go (92%) rename be1-go/internal/{popserver => test}/generatortest/lao.go (97%) rename be1-go/internal/{popserver => test}/generatortest/query.go (95%) rename be1-go/internal/{popserver => test}/generatortest/reaction.go (92%) rename be1-go/internal/{popserver => test}/generatortest/root.go (86%) rename be1-go/internal/{popserver => }/types/hub_params.go (94%) rename be1-go/internal/{popserver => }/types/peers.go (95%) rename be1-go/internal/{popserver => }/types/queries.go (98%) rename be1-go/internal/{popserver => }/types/question.go (100%) rename be1-go/internal/{popserver => }/types/sockets.go (94%) rename be1-go/internal/{popserver => }/types/subscribers.go (96%) rename be1-go/{ => internal/types}/uint53/uint53.go (100%) rename be1-go/{ => internal/types}/uint53/uint53_test.go (100%) rename be1-go/{ => internal}/validation/schema_validator.go (98%) rename be1-go/{ => internal}/validation/schema_validator_test.go (100%) rename be1-go/{ => internal}/validation/validation.go (100%) diff --git a/be1-go/Makefile b/be1-go/Makefile index 12c003f7d3..c328905e6f 100644 --- a/be1-go/Makefile +++ b/be1-go/Makefile @@ -35,10 +35,10 @@ vet: protocol check: test test-cov lint vet protocol: - cp -r ../protocol ./validation + cp -r ../protocol ./internal/validation clean: - rm -rf validation/protocol + rm -rf ./internal/validation/protocol fmt: gofmt -s -w ./ diff --git a/be1-go/cli/cli.go b/be1-go/cli/cli.go index 85e95a77e2..83f9b61542 100644 --- a/be1-go/cli/cli.go +++ b/be1-go/cli/cli.go @@ -7,18 +7,18 @@ import ( "fmt" "net/url" "os" - popstellar "popstellar" - "popstellar/crypto" - "popstellar/internal/popserver" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/sqlite" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/utils" - "popstellar/network" - "popstellar/network/socket" - "popstellar/old/hub" - "popstellar/validation" + "popstellar/internal/crypto" + hub2 "popstellar/internal/hub" + popstellar "popstellar/internal/logger" + network2 "popstellar/internal/network" + "popstellar/internal/network/socket" + "popstellar/internal/old/hub" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/singleton/utils" + "popstellar/internal/sqlite" + "popstellar/internal/validation" "sync" "time" @@ -107,7 +107,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { utils.InitUtils(l, schemaValidator) - state.InitState(l) + state2.InitState(l) config.InitConfig(point, serverPublicKey, serverSecretKey, s.ClientAddress, s.ServerAddress) @@ -117,7 +117,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { } for _, channel := range channels { - alreadyExist, errAnswer := state.HasChannel(channel) + alreadyExist, errAnswer := state2.HasChannel(channel) if errAnswer != nil { return nil, errAnswer } @@ -125,13 +125,13 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { continue } - errAnswer = state.AddChannel(channel) + errAnswer = state2.AddChannel(channel) if errAnswer != nil { return nil, errAnswer } } - return popserver.NewHub(), nil + return hub2.NewHub(), nil } // Serve parses the CLI arguments and spawns a hub and a websocket server for @@ -169,12 +169,12 @@ func Serve(cliCtx *cli.Context) error { h.Start() // Start websocket server for clients - clientSrv := network.NewServer(h, serverConfig.PrivateAddress, serverConfig.ClientPort, socket.ClientSocketType, + clientSrv := network2.NewServer(h, serverConfig.PrivateAddress, serverConfig.ClientPort, socket.ClientSocketType, poplog.With().Str("role", "client websocket").Logger()) clientSrv.Start() // Start a websocket server for remote servers - serverSrv := network.NewServer(h, serverConfig.PrivateAddress, serverConfig.ServerPort, socket.ServerSocketType, + serverSrv := network2.NewServer(h, serverConfig.PrivateAddress, serverConfig.ServerPort, socket.ServerSocketType, poplog.With().Str("role", "server websocket").Logger()) serverSrv.Start() @@ -213,7 +213,7 @@ func Serve(cliCtx *cli.Context) error { go serverConnectionLoop(h, wg, done, serverConfig.OtherServers, updatedServersChan, &connectedServers) // Wait for a Ctrl-C - err = network.WaitAndShutdownServers(cliCtx.Context, nil, clientSrv, serverSrv) + err = network2.WaitAndShutdownServers(cliCtx.Context, nil, clientSrv, serverSrv) if err != nil { return err } diff --git a/be1-go/cli/cli_test.go b/be1-go/cli/cli_test.go index 3854b6df03..51ff4dad40 100644 --- a/be1-go/cli/cli_test.go +++ b/be1-go/cli/cli_test.go @@ -6,11 +6,11 @@ import ( "golang.org/x/xerrors" "io" "os" - "popstellar/crypto" - "popstellar/network" - "popstellar/network/socket" - "popstellar/old/channel/lao" - "popstellar/old/hub/standard_hub" + "popstellar/internal/crypto" + "popstellar/internal/network" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel/lao" + "popstellar/internal/old/hub/standard_hub" "sync" "testing" "time" diff --git a/be1-go/crypto/README.md b/be1-go/internal/crypto/README.md similarity index 100% rename from be1-go/crypto/README.md rename to be1-go/internal/crypto/README.md diff --git a/be1-go/crypto/popcha.rsa b/be1-go/internal/crypto/popcha.rsa similarity index 100% rename from be1-go/crypto/popcha.rsa rename to be1-go/internal/crypto/popcha.rsa diff --git a/be1-go/crypto/popcha.rsa.pub b/be1-go/internal/crypto/popcha.rsa.pub similarity index 100% rename from be1-go/crypto/popcha.rsa.pub rename to be1-go/internal/crypto/popcha.rsa.pub diff --git a/be1-go/crypto/suite.go b/be1-go/internal/crypto/suite.go similarity index 100% rename from be1-go/crypto/suite.go rename to be1-go/internal/crypto/suite.go diff --git a/be1-go/internal/depgraph/README.md b/be1-go/internal/docs/depgraph/README.md similarity index 100% rename from be1-go/internal/depgraph/README.md rename to be1-go/internal/docs/depgraph/README.md diff --git a/be1-go/internal/depgraph/dep.yml b/be1-go/internal/docs/depgraph/dep.yml similarity index 100% rename from be1-go/internal/depgraph/dep.yml rename to be1-go/internal/docs/depgraph/dep.yml diff --git a/be1-go/internal/depgraph/depgraph.go b/be1-go/internal/docs/depgraph/depgraph.go similarity index 100% rename from be1-go/internal/depgraph/depgraph.go rename to be1-go/internal/docs/depgraph/depgraph.go diff --git a/be1-go/internal/popserver/handler/answer.go b/be1-go/internal/handler/answer.go similarity index 81% rename from be1-go/internal/popserver/handler/answer.go rename to be1-go/internal/handler/answer.go index f0cf1c81c7..ca7346a387 100644 --- a/be1-go/internal/popserver/handler/answer.go +++ b/be1-go/internal/handler/answer.go @@ -3,10 +3,10 @@ package handler import ( "encoding/json" "math/rand" - "popstellar" - "popstellar/internal/popserver/state" - "popstellar/message/answer" - "popstellar/message/query/method/message" + "popstellar/internal/logger" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/state" "sort" ) @@ -33,14 +33,14 @@ func handleAnswer(msg []byte) *answer.Error { } if answerMsg.Result == nil { - popstellar.Logger.Info().Msg("received an error, nothing to handle") + logger.Logger.Info().Msg("received an error, nothing to handle") // don't send any error to avoid infinite error loop as a server will // send an error to another server that will create another error return nil } if answerMsg.Result.IsEmpty() { - popstellar.Logger.Info().Msg("expected isn't an answer to a popquery, nothing to handle") + logger.Logger.Info().Msg("expected isn't an answer to a popquery, nothing to handle") return nil } @@ -63,26 +63,26 @@ func handleRumorAnswer(msg answer.Answer) *answer.Error { return errAnswer } - popstellar.Logger.Debug().Msgf("received an answer to rumor query %d", *msg.ID) + logger.Logger.Debug().Msgf("received an answer to rumor query %d", *msg.ID) if msg.Error != nil { - popstellar.Logger.Debug().Msgf("received an answer error to rumor query %d", *msg.ID) + logger.Logger.Debug().Msgf("received an answer error to rumor query %d", *msg.ID) if msg.Error.Code != answer.DuplicateResourceErrorCode { - popstellar.Logger.Debug().Msgf("invalid error code to rumor query %d", *msg.ID) + logger.Logger.Debug().Msgf("invalid error code to rumor query %d", *msg.ID) return nil } stop := rand.Float64() < continueMongering if stop { - popstellar.Logger.Debug().Msgf("stop mongering rumor query %d", *msg.ID) + logger.Logger.Debug().Msgf("stop mongering rumor query %d", *msg.ID) return nil } - popstellar.Logger.Debug().Msgf("continue mongering rumor query %d", *msg.ID) + logger.Logger.Debug().Msgf("continue mongering rumor query %d", *msg.ID) } - popstellar.Logger.Debug().Msgf("sender rumor need to continue sending query %d", *msg.ID) + logger.Logger.Debug().Msgf("sender rumor need to continue sending query %d", *msg.ID) rumor, ok, errAnswer := state.GetRumorFromPastQuery(*msg.ID) if errAnswer != nil { return errAnswer @@ -112,7 +112,7 @@ func handleGetMessagesByIDAnswer(msg answer.Answer) *answer.Error { } errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err) - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) } if len(msgsByChan[channelID]) == 0 { @@ -155,7 +155,7 @@ func tryToHandleMessages(msgsByChannel map[string]map[string]message.Message, so } errAnswer = errAnswer.Wrap(msgID).Wrap("tryToHandleMessages") - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) } if len(msgsByChannel[channelID]) == 0 { diff --git a/be1-go/internal/popserver/handler/answer_test.go b/be1-go/internal/handler/answer_test.go similarity index 93% rename from be1-go/internal/popserver/handler/answer_test.go rename to be1-go/internal/handler/answer_test.go index b6468d2302..bfca1313b8 100644 --- a/be1-go/internal/popserver/handler/answer_test.go +++ b/be1-go/internal/handler/answer_test.go @@ -6,11 +6,11 @@ import ( "fmt" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3/sign/schnorr" - "popstellar/crypto" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/database" "testing" "time" ) diff --git a/be1-go/internal/popserver/handler/channel.go b/be1-go/internal/handler/channel.go similarity index 91% rename from be1-go/internal/popserver/handler/channel.go rename to be1-go/internal/handler/channel.go index cf023ce35c..062643495c 100644 --- a/be1-go/internal/popserver/handler/channel.go +++ b/be1-go/internal/handler/channel.go @@ -5,19 +5,19 @@ import ( "encoding/json" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/sign/schnorr" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/sqlite" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/utils" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/singleton/utils" + "popstellar/internal/sqlite" + "popstellar/internal/validation" ) func handleChannel(channelPath string, msg message.Message, fromRumor bool) *answer.Error { diff --git a/be1-go/internal/popserver/handler/channel_test.go b/be1-go/internal/handler/channel_test.go similarity index 96% rename from be1-go/internal/popserver/handler/channel_test.go rename to be1-go/internal/handler/channel_test.go index 13b9734d39..99544662ed 100644 --- a/be1-go/internal/popserver/handler/channel_test.go +++ b/be1-go/internal/handler/channel_test.go @@ -5,11 +5,11 @@ import ( "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" "golang.org/x/xerrors" - "popstellar/crypto" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/database" + "popstellar/internal/test/generatortest" "testing" "time" ) diff --git a/be1-go/internal/popserver/handler/chirp.go b/be1-go/internal/handler/chirp.go similarity index 96% rename from be1-go/internal/popserver/handler/chirp.go rename to be1-go/internal/handler/chirp.go index ecf4fc7c44..f7ec1f4958 100644 --- a/be1-go/internal/popserver/handler/chirp.go +++ b/be1-go/internal/handler/chirp.go @@ -3,11 +3,11 @@ package handler import ( "encoding/base64" "encoding/json" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" "strings" ) diff --git a/be1-go/internal/popserver/handler/chirp_test.go b/be1-go/internal/handler/chirp_test.go similarity index 86% rename from be1-go/internal/popserver/handler/chirp_test.go rename to be1-go/internal/handler/chirp_test.go index 97fb059931..8ed13cf84a 100644 --- a/be1-go/internal/popserver/handler/chirp_test.go +++ b/be1-go/internal/handler/chirp_test.go @@ -4,26 +4,26 @@ import ( "encoding/base64" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "strings" "testing" "time" ) func Test_handleChannelChirp(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() - state.SetState(subs, peers, queries, hubParams) + state2.SetState(subs, peers, queries, hubParams) organizerBuf, err := base64.URLEncoding.DecodeString(ownerPubBuf64) require.NoError(t, err) @@ -139,7 +139,7 @@ func newChirpAddMsg(t *testing.T, channelID string, sender string, timestamp int msg := generatortest.NewChirpAddMsg(t, sender, nil, timestamp) - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) if isError { @@ -148,7 +148,7 @@ func newChirpAddMsg(t *testing.T, channelID string, sender string, timestamp int chirpNotifyChannelID, _ := strings.CutSuffix(channelID, Social+"/"+msg.Sender) - errAnswer = state.AddChannel(chirpNotifyChannelID) + errAnswer = state2.AddChannel(chirpNotifyChannelID) require.Nil(t, errAnswer) mockRepository.On("StoreChirpMessages", channelID, chirpNotifyChannelID, mock.AnythingOfType("message.Message"), @@ -162,7 +162,7 @@ func newChirpDeleteMsg(t *testing.T, channelID string, sender string, chirpID st msg := generatortest.NewChirpDeleteMsg(t, sender, nil, chirpID, timestamp) - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) if isError { @@ -173,7 +173,7 @@ func newChirpDeleteMsg(t *testing.T, channelID string, sender string, chirpID st chirpNotifyChannelID, _ := strings.CutSuffix(channelID, Social+"/"+msg.Sender) - errAnswer = state.AddChannel(chirpNotifyChannelID) + errAnswer = state2.AddChannel(chirpNotifyChannelID) require.Nil(t, errAnswer) mockRepository.On("StoreChirpMessages", channelID, chirpNotifyChannelID, mock.AnythingOfType("message.Message"), diff --git a/be1-go/internal/popserver/handler/coin.go b/be1-go/internal/handler/coin.go similarity index 89% rename from be1-go/internal/popserver/handler/coin.go rename to be1-go/internal/handler/coin.go index 4a769f8841..3245d3ac3f 100644 --- a/be1-go/internal/popserver/handler/coin.go +++ b/be1-go/internal/handler/coin.go @@ -1,10 +1,10 @@ package handler import ( - "popstellar/internal/popserver/database" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/database" ) func handleChannelCoin(channelPath string, msg message.Message) *answer.Error { diff --git a/be1-go/internal/popserver/handler/coin_test.go b/be1-go/internal/handler/coin_test.go similarity index 86% rename from be1-go/internal/popserver/handler/coin_test.go rename to be1-go/internal/handler/coin_test.go index 99dfc86ff1..58aa2d82a4 100644 --- a/be1-go/internal/popserver/handler/coin_test.go +++ b/be1-go/internal/handler/coin_test.go @@ -6,18 +6,18 @@ import ( "github.com/stretchr/testify/require" "os" "path/filepath" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/repository" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + types2 "popstellar/internal/types" "testing" ) -const coinPath string = "../../../validation/protocol/examples/messageData/coin" +const coinPath string = "../validation/protocol/examples/messageData/coin" type inputTestHandleChannelCoin struct { name string @@ -28,12 +28,12 @@ type inputTestHandleChannelCoin struct { } func Test_handleChannelCoin(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() - state.SetState(subs, peers, queries, hubParams) + state2.SetState(subs, peers, queries, hubParams) mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) @@ -145,11 +145,11 @@ func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, {Id: laoID + "3"}, } - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) for _, s := range sockets { - errAnswer := state.Subscribe(s, channelID) + errAnswer := state2.Subscribe(s, channelID) require.Nil(t, errAnswer) } @@ -181,7 +181,7 @@ func newFailTestHandleChannelCoin(t *testing.T, filename string, name string) in WitnessSignatures: []message.WitnessSignature{}, } - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) return inputTestHandleChannelCoin{ diff --git a/be1-go/internal/popserver/handler/election.go b/be1-go/internal/handler/election.go similarity index 98% rename from be1-go/internal/popserver/handler/election.go rename to be1-go/internal/handler/election.go index 4b793bf052..6dc0a8dc14 100644 --- a/be1-go/internal/popserver/handler/election.go +++ b/be1-go/internal/handler/election.go @@ -6,13 +6,13 @@ import ( "encoding/binary" "encoding/json" "fmt" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/types" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/types" "sort" ) diff --git a/be1-go/internal/popserver/handler/election_test.go b/be1-go/internal/handler/election_test.go similarity index 95% rename from be1-go/internal/popserver/handler/election_test.go rename to be1-go/internal/handler/election_test.go index 4f56d46d85..afaa401042 100644 --- a/be1-go/internal/popserver/handler/election_test.go +++ b/be1-go/internal/handler/election_test.go @@ -6,15 +6,15 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - state "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "testing" ) @@ -24,10 +24,10 @@ func Test_handleChannelElection(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() ownerPubBuf, err := base64.URLEncoding.DecodeString(ownerPubBuf64) require.NoError(t, err) @@ -41,7 +41,7 @@ func Test_handleChannelElection(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") - state.SetState(subs, peers, queries, hubParams) + state2.SetState(subs, peers, queries, hubParams) laoID := base64.URLEncoding.EncodeToString([]byte("laoID")) electionID := base64.URLEncoding.EncodeToString([]byte("electionID")) @@ -108,7 +108,7 @@ func Test_handleChannelElection(t *testing.T) { electionID = base64.URLEncoding.EncodeToString([]byte("electionID3")) channelPath = "/root/" + laoID + "/" + electionID - errAnswer := state.AddChannel(channelPath) + errAnswer := state2.AddChannel(channelPath) require.Nil(t, errAnswer) // Test 6: Success when ElectionOpen is valid @@ -204,7 +204,7 @@ func Test_handleChannelElection(t *testing.T) { registeredVotes := messagedata.Hash("voteID1", "voteID2", "voteID3") - errAnswer = state.AddChannel(channelPath) + errAnswer = state2.AddChannel(channelPath) require.Nil(t, errAnswer) // Test 13: Success when ElectionEnd is valid @@ -278,7 +278,7 @@ func Test_handleChannelElection(t *testing.T) { channelPath = "/root/" + laoID + "/" + electionID //Test 18 Error when VoteCastVote question is not present in election setup - questions := map[string]types.Question{ + questions := map[string]types2.Question{ base64.URLEncoding.EncodeToString([]byte("questionID2")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID2")))}, base64.URLEncoding.EncodeToString([]byte("questionID3")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID3")))}, } @@ -445,10 +445,10 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } if votes != "" { - questions := map[string]types.Question{ + questions := map[string]types2.Question{ "questionID1": { ID: []byte("questionID1"), - ValidVotes: map[string]types.ValidVote{ + ValidVotes: map[string]types2.ValidVote{ "voteID1": { ID: "voteID1", }, @@ -459,7 +459,7 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI }, "questionID2": { ID: []byte("questionID2"), - ValidVotes: map[string]types.ValidVote{ + ValidVotes: map[string]types2.ValidVote{ "voteID3": { ID: "voteID3", }, @@ -480,7 +480,7 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath, state, electionType string, - createdAt int64, votes []generatortest.VoteInt, questions map[string]types.Question, owner kyber.Point, + createdAt int64, votes []generatortest.VoteInt, questions map[string]types2.Question, owner kyber.Point, mockRepository *repository.MockRepository, isEroor bool) message.Message { msg := generatortest.NewVoteCastVoteIntMsg(t, sender, laoID, electionID, 1, votes, nil) @@ -518,7 +518,7 @@ func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath } func newVoteCastVoteStringMsg(t *testing.T, sender, laoID, electionID, electionPath, electionType string, - createdAt int64, votes []generatortest.VoteString, questions map[string]types.Question, owner kyber.Point, + createdAt int64, votes []generatortest.VoteString, questions map[string]types2.Question, owner kyber.Point, mockRepository *repository.MockRepository) message.Message { msg := generatortest.NewVoteCastVoteStringMsg(t, sender, laoID, electionID, 1, votes, nil) diff --git a/be1-go/internal/popserver/handler/federation.go b/be1-go/internal/handler/federation.go similarity index 94% rename from be1-go/internal/popserver/handler/federation.go rename to be1-go/internal/handler/federation.go index 5c00a07c89..fd96bd34a8 100644 --- a/be1-go/internal/popserver/handler/federation.go +++ b/be1-go/internal/handler/federation.go @@ -8,17 +8,17 @@ import ( "fmt" "github.com/gorilla/websocket" "go.dedis.ch/kyber/v3/sign/schnorr" - "popstellar" - "popstellar/crypto" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/state" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" + "popstellar/internal/crypto" + "popstellar/internal/logger" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" "strings" "time" ) @@ -169,7 +169,7 @@ func handleExpect(msg message.Message, channelPath string) *answer.Error { } remoteChannel := fmt.Sprintf(channelPattern, federationExpect.LaoId) - _ = state.AddChannel(remoteChannel) + _ = state2.AddChannel(remoteChannel) err = db.StoreMessageAndData(channelPath, msg) if err != nil { @@ -231,8 +231,8 @@ func handleInit(msg message.Message, channelPath string) *answer.Error { //Force the remote server to be subscribed to /root//federation remoteChannel := fmt.Sprintf(channelPattern, federationInit.LaoId) - _ = state.AddChannel(remoteChannel) - errAnswer = state.Subscribe(remote, remoteChannel) + _ = state2.AddChannel(remoteChannel) + errAnswer = state2.Subscribe(remote, remoteChannel) if errAnswer != nil { return errAnswer.Wrap("handleFederationInit") } @@ -255,7 +255,7 @@ func handleInit(msg message.Message, channelPath string) *answer.Error { } // Subscribe to /root//federation on the remote server - errAnswer = state.SendToAll(subscribeBytes, remoteChannel) + errAnswer = state2.SendToAll(subscribeBytes, remoteChannel) if errAnswer != nil { return errAnswer.Wrap("handleFederationInit") } @@ -483,28 +483,28 @@ func connectTo(serverAddress string) (socket.Socket, *answer.Error) { return nil, errAnswer.Wrap("connectTo") } - messageChan, errAnswer := state.GetMessageChan() + messageChan, errAnswer := state2.GetMessageChan() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - closedSockets, errAnswer := state.GetClosedSockets() + closedSockets, errAnswer := state2.GetClosedSockets() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - wg, errAnswer := state.GetWaitGroup() + wg, errAnswer := state2.GetWaitGroup() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - stopChan, errAnswer := state.GetStopChan() + stopChan, errAnswer := state2.GetStopChan() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } client := socket.NewClientSocket(messageChan, closedSockets, ws, wg, - stopChan, popstellar.Logger) + stopChan, logger.Logger) wg.Add(2) @@ -583,7 +583,7 @@ func publishTo(msg message.Message, channel string) *answer.Error { return errAnswer.Wrap("publishTo") } - errAnswer := state.SendToAll(publishBytes, channel) + errAnswer := state2.SendToAll(publishBytes, channel) if errAnswer != nil { return errAnswer.Wrap("publishTo") } diff --git a/be1-go/internal/popserver/handler/federation_test.go b/be1-go/internal/handler/federation_test.go similarity index 94% rename from be1-go/internal/popserver/handler/federation_test.go rename to be1-go/internal/handler/federation_test.go index 8ed0ca1264..74fad3e881 100644 --- a/be1-go/internal/popserver/handler/federation_test.go +++ b/be1-go/internal/handler/federation_test.go @@ -10,16 +10,16 @@ import ( "github.com/stretchr/testify/require" "net" "net/http" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/network/socket" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "testing" "time" ) @@ -30,10 +30,10 @@ func Test_handleChannelFederation(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -321,10 +321,10 @@ func Test_handleRequestChallenge(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -353,9 +353,8 @@ func Test_handleRequestChallenge(t *testing.T) { mockRepository.On("StoreMessageAndData", channelPath, mock.AnythingOfType("message.Message")).Return(nil) - errAnswer = handleRequestChallenge(generatortest. - NewFederationChallengeRequest(t, organizer, time.Now().Unix(), - organizerSk), channelPath) + errAnswer = handleRequestChallenge(generatortest.NewFederationChallengeRequest(t, organizer, time.Now().Unix(), + organizerSk), channelPath) require.Nil(t, errAnswer) require.NotNil(t, fakeSocket.Msg) @@ -378,10 +377,10 @@ func Test_handleFederationExpect(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -438,10 +437,10 @@ func Test_handleFederationInit(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -521,10 +520,10 @@ func Test_handleFederationChallenge(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -628,10 +627,10 @@ func Test_handleFederationResult(t *testing.T) { mockRepository := repository.NewMockRepository(t) database.SetDatabase(mockRepository) - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() organizerPk, organizerSk := generateKeys() organizer2Pk, organizer2Sk := generateKeys() diff --git a/be1-go/internal/popserver/handler/incoming_message.go b/be1-go/internal/handler/incoming_message.go similarity index 82% rename from be1-go/internal/popserver/handler/incoming_message.go rename to be1-go/internal/handler/incoming_message.go index e908cc2082..1b9d048e46 100644 --- a/be1-go/internal/popserver/handler/incoming_message.go +++ b/be1-go/internal/handler/incoming_message.go @@ -1,11 +1,11 @@ package handler import ( - "popstellar/internal/popserver/utils" - "popstellar/message" - "popstellar/message/answer" - "popstellar/network/socket" - "popstellar/validation" + "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/utils" + "popstellar/internal/validation" ) func HandleIncomingMessage(socket socket.Socket, msg []byte) error { diff --git a/be1-go/internal/popserver/handler/incoming_message_test.go b/be1-go/internal/handler/incoming_message_test.go similarity index 75% rename from be1-go/internal/popserver/handler/incoming_message_test.go rename to be1-go/internal/handler/incoming_message_test.go index 6b51662aa1..f022405fc8 100644 --- a/be1-go/internal/popserver/handler/incoming_message_test.go +++ b/be1-go/internal/handler/incoming_message_test.go @@ -7,10 +7,10 @@ import ( "github.com/stretchr/testify/require" "io" "os" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/utils" - "popstellar/network/socket" - "popstellar/validation" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/utils" + generatortest2 "popstellar/internal/test/generatortest" + "popstellar/internal/validation" "testing" ) @@ -43,18 +43,18 @@ func Test_handleIncomingMessage(t *testing.T) { args = append(args, input{ name: "Test 1", - message: generatortest.NewNothingQuery(t, 999), + message: generatortest2.NewNothingQuery(t, 999), contains: "invalid json", }) // Test 2: failed to handled popanswer because wrong publish popanswer format - msg := generatortest.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) + msg := generatortest2.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) msg.MessageID = "wrong messageID" args = append(args, input{ name: "Test 2", - message: generatortest.NewPublishQuery(t, 1, "/root/lao1", msg), + message: generatortest2.NewPublishQuery(t, 1, "/root/lao1", msg), contains: "invalid json", }) diff --git a/be1-go/internal/popserver/handler/lao.go b/be1-go/internal/handler/lao.go similarity index 98% rename from be1-go/internal/popserver/handler/lao.go rename to be1-go/internal/handler/lao.go index d9a925db2e..98fdaddf3d 100644 --- a/be1-go/internal/popserver/handler/lao.go +++ b/be1-go/internal/handler/lao.go @@ -6,13 +6,13 @@ import ( "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/sign/schnorr" "golang.org/x/exp/slices" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/state" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" "strings" ) diff --git a/be1-go/internal/popserver/handler/lao_test.go b/be1-go/internal/handler/lao_test.go similarity index 96% rename from be1-go/internal/popserver/handler/lao_test.go rename to be1-go/internal/handler/lao_test.go index 7e3d23255f..d4ae42d9b5 100644 --- a/be1-go/internal/popserver/handler/lao_test.go +++ b/be1-go/internal/handler/lao_test.go @@ -5,15 +5,15 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "strconv" "strings" "testing" @@ -21,10 +21,10 @@ import ( ) func Test_handleChannelLao(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) diff --git a/be1-go/internal/popserver/handler/publish.go b/be1-go/internal/handler/publish.go similarity index 65% rename from be1-go/internal/popserver/handler/publish.go rename to be1-go/internal/handler/publish.go index a781d1885d..885f5ad6da 100644 --- a/be1-go/internal/popserver/handler/publish.go +++ b/be1-go/internal/handler/publish.go @@ -2,12 +2,12 @@ package handler import ( "encoding/json" - "popstellar" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/state" - "popstellar/message/answer" - "popstellar/message/query/method" - "popstellar/network/socket" + "popstellar/internal/logger" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" "strings" ) @@ -35,25 +35,25 @@ func handlePublish(socket socket.Socket, msg []byte) (*int, *answer.Error) { db, errAnswer := database.GetRumorSenderRepositoryInstance() if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) return nil, nil } - popstellar.Logger.Debug().Msgf("sender rumor need to add message %s", publish.Params.Message.MessageID) + logger.Logger.Debug().Msgf("sender rumor need to add message %s", publish.Params.Message.MessageID) nbMessagesInsideRumor, err := db.AddMessageToMyRumor(publish.Params.Message.MessageID) if err != nil { - popstellar.Logger.Error().Err(err) + logger.Logger.Error().Err(err) return nil, nil } if nbMessagesInsideRumor < thresholdMessagesByRumor { - popstellar.Logger.Debug().Msgf("no enough message to send rumor %s", publish.Params.Message.MessageID) + logger.Logger.Debug().Msgf("no enough message to send rumor %s", publish.Params.Message.MessageID) return nil, nil } errAnswer = state.NotifyResetRumorSender() if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) } return nil, nil diff --git a/be1-go/internal/popserver/handler/query.go b/be1-go/internal/handler/query.go similarity index 90% rename from be1-go/internal/popserver/handler/query.go rename to be1-go/internal/handler/query.go index a2bdab6901..7dee00444c 100644 --- a/be1-go/internal/popserver/handler/query.go +++ b/be1-go/internal/handler/query.go @@ -2,14 +2,14 @@ package handler import ( "encoding/json" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/state" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/network/socket" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" ) func handleQuery(socket socket.Socket, msg []byte) *answer.Error { @@ -64,12 +64,12 @@ func handleGreetServer(socket socket.Socket, byteMessage []byte) (*int, *answer. return nil, errAnswer.Wrap("handleGreetServer") } - errAnswer := state.AddPeerInfo(socket.ID(), greetServer.Params) + errAnswer := state2.AddPeerInfo(socket.ID(), greetServer.Params) if errAnswer != nil { return nil, errAnswer.Wrap("handleGreetServer") } - isGreeted, errAnswer := state.IsPeerGreeted(socket.ID()) + isGreeted, errAnswer := state2.IsPeerGreeted(socket.ID()) if errAnswer != nil { return nil, errAnswer.Wrap("handleGreetServer") } @@ -106,7 +106,7 @@ func handleGreetServer(socket socket.Socket, byteMessage []byte) (*int, *answer. socket.Send(buf) - errAnswer = state.AddPeerGreeted(socket.ID()) + errAnswer = state2.AddPeerGreeted(socket.ID()) if errAnswer != nil { return nil, errAnswer.Wrap("handleGreetServer") } @@ -128,7 +128,7 @@ func handleSubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { return &subscribe.ID, errAnswer.Wrap("handleSubscribe") } - errAnswer := state.Subscribe(socket, subscribe.Params.Channel) + errAnswer := state2.Subscribe(socket, subscribe.Params.Channel) if errAnswer != nil { return &subscribe.ID, errAnswer.Wrap("handleSubscribe") } @@ -152,7 +152,7 @@ func handleUnsubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") } - errAnswer := state.Unsubscribe(socket, unsubscribe.Params.Channel) + errAnswer := state2.Unsubscribe(socket, unsubscribe.Params.Channel) if errAnswer != nil { return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") } @@ -211,7 +211,7 @@ func handleHeartbeat(socket socket.Socket, byteMessage []byte) *answer.Error { return nil } - queryId, errAnswer := state.GetNextID() + queryId, errAnswer := state2.GetNextID() if errAnswer != nil { return errAnswer.Wrap("handleHeartbeat") } @@ -235,7 +235,7 @@ func handleHeartbeat(socket socket.Socket, byteMessage []byte) *answer.Error { socket.Send(buf) - errAnswer = state.AddQuery(queryId, getMessagesById) + errAnswer = state2.AddQuery(queryId, getMessagesById) if errAnswer != nil { return errAnswer.Wrap("handleHeartbeat") } diff --git a/be1-go/internal/popserver/handler/query_test.go b/be1-go/internal/handler/query_test.go similarity index 82% rename from be1-go/internal/popserver/handler/query_test.go rename to be1-go/internal/handler/query_test.go index 9d12702240..3f1e496b2f 100644 --- a/be1-go/internal/popserver/handler/query_test.go +++ b/be1-go/internal/handler/query_test.go @@ -4,16 +4,16 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "golang.org/x/xerrors" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + generatortest2 "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "testing" ) @@ -28,7 +28,7 @@ func Test_handleQuery(t *testing.T) { // Test 1: failed to handled popquery because unknown method - msg := generatortest.NewNothingQuery(t, 999) + msg := generatortest2.NewNothingQuery(t, 999) args = append(args, input{ name: "Test 1", @@ -49,10 +49,10 @@ func Test_handleQuery(t *testing.T) { } func Test_handleGreetServer(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -72,7 +72,7 @@ func Test_handleGreetServer(t *testing.T) { args := make([]input, 0) - greetServer := generatortest.NewGreetServerQuery(t, "pk", "client", "server") + greetServer := generatortest2.NewGreetServerQuery(t, "pk", "client", "server") // Test 1: reply with greet server when receiving a greet server from a new server @@ -136,10 +136,10 @@ func Test_handleGreetServer(t *testing.T) { } func Test_handleSubscribe(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -169,7 +169,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generatortest2.NewSubscribeQuery(t, ID, channel), isError: false, }) @@ -184,7 +184,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generatortest2.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to unknown channel", }) @@ -200,7 +200,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generatortest2.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to root channel", }) @@ -225,10 +225,10 @@ func Test_handleSubscribe(t *testing.T) { } func Test_handleUnsubscribe(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -261,7 +261,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generatortest2.NewUnsubscribeQuery(t, ID, channel), isError: false, }) @@ -279,7 +279,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generatortest2.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from a channel not subscribed", }) @@ -295,7 +295,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generatortest2.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from unknown channel", }) @@ -311,7 +311,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generatortest2.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from root channel", }) @@ -337,10 +337,10 @@ func Test_handleUnsubscribe(t *testing.T) { } func Test_handleCatchUp(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -365,10 +365,10 @@ func Test_handleCatchUp(t *testing.T) { ID := 1 channel := "/root/lao1" messagesToCatchUp := []message.Message{ - generatortest.NewNothingMsg(t, "sender1", nil), - generatortest.NewNothingMsg(t, "sender2", nil), - generatortest.NewNothingMsg(t, "sender3", nil), - generatortest.NewNothingMsg(t, "sender4", nil), + generatortest2.NewNothingMsg(t, "sender1", nil), + generatortest2.NewNothingMsg(t, "sender2", nil), + generatortest2.NewNothingMsg(t, "sender3", nil), + generatortest2.NewNothingMsg(t, "sender4", nil), } mockRepository.On("GetAllMessagesFromChannel", channel).Return(messagesToCatchUp, nil) @@ -377,7 +377,7 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest.NewCatchupQuery(t, ID, channel), + message: generatortest2.NewCatchupQuery(t, ID, channel), expected: messagesToCatchUp, isError: false, }) @@ -395,7 +395,7 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest.NewCatchupQuery(t, ID, channel), + message: generatortest2.NewCatchupQuery(t, ID, channel), isError: true, contains: "DB is disconnected", }) @@ -419,10 +419,10 @@ func Test_handleCatchUp(t *testing.T) { } func Test_handleHeartbeat(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -475,7 +475,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 1", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs1), + message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs1), expected: expected1, isError: false, }) @@ -496,7 +496,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 2", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs2), + message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs2), isError: false, }) @@ -521,7 +521,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "failed to popquery DB", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs3), + message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs3), isError: true, contains: "DB is disconnected", }) @@ -551,10 +551,10 @@ func Test_handleHeartbeat(t *testing.T) { } func Test_handleGetMessagesByID(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -580,14 +580,14 @@ func Test_handleGetMessagesByID(t *testing.T) { expected1 := make(map[string][]message.Message) expected1["/root"] = []message.Message{ - generatortest.NewNothingMsg(t, "sender1", nil), - generatortest.NewNothingMsg(t, "sender2", nil), - generatortest.NewNothingMsg(t, "sender3", nil), - generatortest.NewNothingMsg(t, "sender4", nil), + generatortest2.NewNothingMsg(t, "sender1", nil), + generatortest2.NewNothingMsg(t, "sender2", nil), + generatortest2.NewNothingMsg(t, "sender3", nil), + generatortest2.NewNothingMsg(t, "sender4", nil), } expected1["/root/lao1"] = []message.Message{ - generatortest.NewNothingMsg(t, "sender5", nil), - generatortest.NewNothingMsg(t, "sender6", nil), + generatortest2.NewNothingMsg(t, "sender5", nil), + generatortest2.NewNothingMsg(t, "sender6", nil), } paramsGetMessagesByID1 := make(map[string][]string) @@ -604,7 +604,7 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), + message: generatortest2.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), expected: expected1, isError: false, }) @@ -623,7 +623,7 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), + message: generatortest2.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), isError: true, contains: "DB is disconnected", }) diff --git a/be1-go/internal/popserver/handler/reaction.go b/be1-go/internal/handler/reaction.go similarity index 94% rename from be1-go/internal/popserver/handler/reaction.go rename to be1-go/internal/handler/reaction.go index 75edff974c..036e385b44 100644 --- a/be1-go/internal/popserver/handler/reaction.go +++ b/be1-go/internal/handler/reaction.go @@ -1,10 +1,10 @@ package handler import ( - "popstellar/internal/popserver/database" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/database" "strings" ) diff --git a/be1-go/internal/popserver/handler/reaction_test.go b/be1-go/internal/handler/reaction_test.go similarity index 92% rename from be1-go/internal/popserver/handler/reaction_test.go rename to be1-go/internal/handler/reaction_test.go index f9b54f7b66..fcf261708b 100644 --- a/be1-go/internal/popserver/handler/reaction_test.go +++ b/be1-go/internal/handler/reaction_test.go @@ -3,26 +3,26 @@ package handler import ( "encoding/base64" "github.com/stretchr/testify/require" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "strings" "testing" "time" ) func Test_handleChannelReaction(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() - state.SetState(subs, peers, queries, hubParams) + state2.SetState(subs, peers, queries, hubParams) organizerBuf, err := base64.URLEncoding.DecodeString(ownerPubBuf64) require.NoError(t, err) @@ -226,7 +226,7 @@ func newReactionAddMsg(t *testing.T, channelID string, sender string, reactionCo msg := generatortest.NewReactionAddMsg(t, sender, nil, reactionCodePoint, chirpID, timestamp) - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) laoPath, _ := strings.CutSuffix(channelID, Social+Reactions) @@ -248,7 +248,7 @@ func newReactionDeleteMsg(t *testing.T, channelID string, sender string, reactio msg := generatortest.NewReactionDeleteMsg(t, sender, nil, reactionID, timestamp) - errAnswer := state.AddChannel(channelID) + errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) laoPath, _ := strings.CutSuffix(channelID, Social+Reactions) diff --git a/be1-go/internal/popserver/handler/root.go b/be1-go/internal/handler/root.go similarity index 94% rename from be1-go/internal/popserver/handler/root.go rename to be1-go/internal/handler/root.go index e4f3b4b889..1b84eec8e2 100644 --- a/be1-go/internal/popserver/handler/root.go +++ b/be1-go/internal/handler/root.go @@ -3,14 +3,14 @@ package handler import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/sqlite" - "popstellar/internal/popserver/state" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/sqlite" ) const ( @@ -158,7 +158,7 @@ func createLaoAndChannels(msg, laoGreetMsg message.Message, organizerPubBuf []by } for channelPath := range channels { - errAnswer := state.AddChannel(channelPath) + errAnswer := state2.AddChannel(channelPath) if errAnswer != nil { return errAnswer.Wrap("createLaoAndSubChannels") } @@ -167,7 +167,7 @@ func createLaoAndChannels(msg, laoGreetMsg message.Message, organizerPubBuf []by } func createLaoGreet(organizerBuf []byte, laoID string) (message.Message, *answer.Error) { - peersInfo, errAnswer := state.GetAllPeersInfo() + peersInfo, errAnswer := state2.GetAllPeersInfo() if errAnswer != nil { return message.Message{}, errAnswer.Wrap("createAndSendLaoGreet") } diff --git a/be1-go/internal/popserver/handler/root_test.go b/be1-go/internal/handler/root_test.go similarity index 84% rename from be1-go/internal/popserver/handler/root_test.go rename to be1-go/internal/handler/root_test.go index 91710c74fb..7df52fe755 100644 --- a/be1-go/internal/popserver/handler/root_test.go +++ b/be1-go/internal/handler/root_test.go @@ -5,16 +5,16 @@ import ( "fmt" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "popstellar/crypto" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/database/repository" - "popstellar/internal/popserver/database/sqlite" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/repository" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/sqlite" + generatortest2 "popstellar/internal/test/generatortest" + types2 "popstellar/internal/types" "testing" "time" ) @@ -35,10 +35,10 @@ type input struct { } func Test_handleChannelRoot(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() + subs := types2.NewSubscribers() + queries := types2.NewQueries(&noLog) + peers := types2.NewPeers() + hubParams := types2.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -89,7 +89,7 @@ func Test_handleChannelRoot(t *testing.T) { // Test 4: error when message data is not lao_create args = append(args, input{ name: "Test 4", - msg: generatortest.NewNothingMsg(t, owner, nil), + msg: generatortest2.NewNothingMsg(t, owner, nil), isError: true, contains: "failed to validate schema", }) @@ -123,7 +123,7 @@ func newLaoCreateMsg(t *testing.T, organizer, sender, laoName string, mockReposi goodLaoName, ) - msg := generatortest.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) + msg := generatortest2.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) mockRepository.On("HasChannel", RootPrefix+laoID).Return(false, nil) if !isError { diff --git a/be1-go/internal/popserver/handler/rumor.go b/be1-go/internal/handler/rumor.go similarity index 80% rename from be1-go/internal/popserver/handler/rumor.go rename to be1-go/internal/handler/rumor.go index c93eed48c1..39a1881757 100644 --- a/be1-go/internal/popserver/handler/rumor.go +++ b/be1-go/internal/handler/rumor.go @@ -2,14 +2,14 @@ package handler import ( "encoding/json" - "popstellar" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/utils" - "popstellar/message/answer" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" + "popstellar/internal/logger" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/singleton/utils" "sort" ) @@ -22,7 +22,7 @@ func handleRumor(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handleRumor") } - popstellar.Logger.Debug().Msgf("received rumor %s-%d from query %d", + logger.Logger.Debug().Msgf("received rumor %s-%d from query %d", rumor.Params.SenderID, rumor.Params.RumorID, rumor.ID) db, errAnswer := database.GetQueryRepositoryInstance() @@ -101,7 +101,7 @@ func tryHandlingMessages(channel string, unprocessedMsgs []message.Message) ([]m } errAnswer = errAnswer.Wrap(msg.MessageID).Wrap("tryHandlingMessages") - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) } if len(unprocessedMsgs) == 0 { @@ -130,29 +130,29 @@ func sortChannels(msgsByChannel map[string][]message.Message) []string { } func SendRumor(socket socket.Socket, rumor method.Rumor) { - id, errAnswer := state.GetNextID() + id, errAnswer := state2.GetNextID() if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) return } rumor.ID = id - errAnswer = state.AddRumorQuery(id, rumor) + errAnswer = state2.AddRumorQuery(id, rumor) if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) return } buf, err := json.Marshal(rumor) if err != nil { - popstellar.Logger.Error().Err(err) + logger.Logger.Error().Err(err) return } - popstellar.Logger.Debug().Msgf("sending rumor %s-%d query %d", rumor.Params.SenderID, rumor.Params.RumorID, rumor.ID) - errAnswer = state.SendRumor(socket, rumor.Params.SenderID, rumor.Params.RumorID, buf) + logger.Logger.Debug().Msgf("sending rumor %s-%d query %d", rumor.Params.SenderID, rumor.Params.RumorID, rumor.ID) + errAnswer = state2.SendRumor(socket, rumor.Params.SenderID, rumor.Params.RumorID, buf) if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) } } diff --git a/be1-go/internal/popserver/hub.go b/be1-go/internal/hub/hub.go similarity index 71% rename from be1-go/internal/popserver/hub.go rename to be1-go/internal/hub/hub.go index 97ad6f617b..b9a382f61e 100644 --- a/be1-go/internal/popserver/hub.go +++ b/be1-go/internal/hub/hub.go @@ -1,18 +1,18 @@ -package popserver +package hub import ( "encoding/json" "golang.org/x/xerrors" - "popstellar" - "popstellar/internal/popserver/config" - "popstellar/internal/popserver/database" - "popstellar/internal/popserver/handler" - "popstellar/internal/popserver/state" - "popstellar/internal/popserver/utils" - jsonrpc "popstellar/message" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/network/socket" + "popstellar/internal/handler" + "popstellar/internal/logger" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/database" + state2 "popstellar/internal/singleton/state" + "popstellar/internal/singleton/utils" "sync" "time" ) @@ -30,27 +30,27 @@ type Hub struct { } func NewHub() *Hub { - wg, errAnswer := state.GetWaitGroup() + wg, errAnswer := state2.GetWaitGroup() if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) return nil } - messageChan, errAnswer := state.GetMessageChan() + messageChan, errAnswer := state2.GetMessageChan() if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) return nil } - stop, errAnswer := state.GetStopChan() + stop, errAnswer := state2.GetStopChan() if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) return nil } - closedSockets, errAnswer := state.GetClosedSockets() + closedSockets, errAnswer := state2.GetClosedSockets() if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) return nil } @@ -63,9 +63,9 @@ func NewHub() *Hub { } func (h *Hub) NotifyNewServer(socket socket.Socket) { - errAnswer := state.Upsert(socket) + errAnswer := state2.Upsert(socket) if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) } } @@ -90,23 +90,23 @@ func (h *Hub) Start() { ticker := time.NewTicker(rumorDelay) defer ticker.Stop() defer h.wg.Done() - defer popstellar.Logger.Info().Msg("stopping rumor sender") + defer logger.Logger.Info().Msg("stopping rumor sender") - popstellar.Logger.Info().Msg("starting rumor sender") + logger.Logger.Info().Msg("starting rumor sender") - reset, errAnswer := state.GetResetRumorSender() + reset, errAnswer := state2.GetResetRumorSender() if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) return } for { select { case <-ticker.C: - popstellar.Logger.Debug().Msgf("sender rumor trigerred") + logger.Logger.Debug().Msgf("sender rumor trigerred") h.tryToSendRumor() case <-reset: - popstellar.Logger.Debug().Msgf("sender rumor reset") + logger.Logger.Debug().Msgf("sender rumor reset") ticker.Reset(rumorDelay) h.tryToSendRumor() case <-h.stop: @@ -131,7 +131,7 @@ func (h *Hub) Start() { } case socketID := <-h.closedSockets: utils.LogInfo("stopping the Socket " + socketID) - state.UnsubscribeFromAll(socketID) + state2.UnsubscribeFromAll(socketID) case <-h.stop: utils.LogInfo("stopping the Hub") return @@ -182,7 +182,7 @@ func (h *Hub) SendGreetServer(socket socket.Socket) error { socket.Send(buf) - errAnswer = state.AddPeerGreeted(socket.ID()) + errAnswer = state2.AddPeerGreeted(socket.ID()) if errAnswer != nil { return xerrors.Errorf(errAnswer.Error()) } @@ -203,29 +203,29 @@ func (h *Hub) sendHeartbeatToServers() { buf, err := json.Marshal(heartbeatMessage) if err != nil { - popstellar.Logger.Err(err) + logger.Logger.Err(err) } - errAnswer := state.SendToAllServer(buf) + errAnswer := state2.SendToAllServer(buf) if errAnswer != nil { - popstellar.Logger.Err(errAnswer) + logger.Logger.Err(errAnswer) } } func (h *Hub) tryToSendRumor() { db, errAnswer := database.GetRumorSenderRepositoryInstance() if errAnswer != nil { - popstellar.Logger.Error().Err(errAnswer) + logger.Logger.Error().Err(errAnswer) return } ok, rumor, err := db.GetAndIncrementMyRumor() if err != nil { - popstellar.Logger.Error().Err(err) + logger.Logger.Error().Err(err) return } if !ok { - popstellar.Logger.Debug().Msg("no new rumor to send") + logger.Logger.Debug().Msg("no new rumor to send") return } diff --git a/be1-go/logger.go b/be1-go/internal/logger/logger.go similarity index 98% rename from be1-go/logger.go rename to be1-go/internal/logger/logger.go index 725784ea3c..35a3ae1e81 100644 --- a/be1-go/logger.go +++ b/be1-go/internal/logger/logger.go @@ -8,7 +8,7 @@ // // LLVL=error ./pop server --pk "" serve // LLVL=warn ./pop server --pk "" serve -package popstellar +package logger import ( "os" diff --git a/be1-go/message/answer/answer.go b/be1-go/internal/message/answer/answer.go similarity index 97% rename from be1-go/message/answer/answer.go rename to be1-go/internal/message/answer/answer.go index 53f2eff018..b26cff531d 100644 --- a/be1-go/message/answer/answer.go +++ b/be1-go/internal/message/answer/answer.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "golang.org/x/xerrors" - message "popstellar/message" + message "popstellar/internal/message" ) // Answer defines the JSON RPC answer message diff --git a/be1-go/message/answer/error.go b/be1-go/internal/message/answer/error.go similarity index 100% rename from be1-go/message/answer/error.go rename to be1-go/internal/message/answer/error.go diff --git a/be1-go/message/jsonRPC.go b/be1-go/internal/message/jsonRPC.go similarity index 100% rename from be1-go/message/jsonRPC.go rename to be1-go/internal/message/jsonRPC.go diff --git a/be1-go/message/messagedata/authenticate_user.go b/be1-go/internal/message/messagedata/authenticate_user.go similarity index 98% rename from be1-go/message/messagedata/authenticate_user.go rename to be1-go/internal/message/messagedata/authenticate_user.go index f0f28ecf9f..18b8a85fdf 100644 --- a/be1-go/message/messagedata/authenticate_user.go +++ b/be1-go/internal/message/messagedata/authenticate_user.go @@ -4,7 +4,7 @@ import ( "encoding/base64" "go.dedis.ch/kyber/v3/sign/schnorr" "golang.org/x/xerrors" - "popstellar/crypto" + "popstellar/internal/crypto" ) // AuthenticateUser is a message containing the user authentication information diff --git a/be1-go/message/messagedata/chirp_add.go b/be1-go/internal/message/messagedata/chirp_add.go similarity index 100% rename from be1-go/message/messagedata/chirp_add.go rename to be1-go/internal/message/messagedata/chirp_add.go diff --git a/be1-go/message/messagedata/chirp_broadcast.go b/be1-go/internal/message/messagedata/chirp_broadcast.go similarity index 100% rename from be1-go/message/messagedata/chirp_broadcast.go rename to be1-go/internal/message/messagedata/chirp_broadcast.go diff --git a/be1-go/message/messagedata/chirp_delete.go b/be1-go/internal/message/messagedata/chirp_delete.go similarity index 100% rename from be1-go/message/messagedata/chirp_delete.go rename to be1-go/internal/message/messagedata/chirp_delete.go diff --git a/be1-go/message/messagedata/chirp_notify_add.go b/be1-go/internal/message/messagedata/chirp_notify_add.go similarity index 100% rename from be1-go/message/messagedata/chirp_notify_add.go rename to be1-go/internal/message/messagedata/chirp_notify_add.go diff --git a/be1-go/message/messagedata/chirp_notify_delete.go b/be1-go/internal/message/messagedata/chirp_notify_delete.go similarity index 100% rename from be1-go/message/messagedata/chirp_notify_delete.go rename to be1-go/internal/message/messagedata/chirp_notify_delete.go diff --git a/be1-go/message/messagedata/coin_post_transaction.go b/be1-go/internal/message/messagedata/coin_post_transaction.go similarity index 98% rename from be1-go/message/messagedata/coin_post_transaction.go rename to be1-go/internal/message/messagedata/coin_post_transaction.go index d304ab54ed..e1770cfc81 100644 --- a/be1-go/message/messagedata/coin_post_transaction.go +++ b/be1-go/internal/message/messagedata/coin_post_transaction.go @@ -5,9 +5,9 @@ import ( "encoding/base64" "go.dedis.ch/kyber/v3/sign/schnorr" "golang.org/x/xerrors" - "popstellar/crypto" - "popstellar/message/answer" - "popstellar/uint53" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/types/uint53" "strconv" ) diff --git a/be1-go/message/messagedata/consensus_accept.go b/be1-go/internal/message/messagedata/consensus_accept.go similarity index 100% rename from be1-go/message/messagedata/consensus_accept.go rename to be1-go/internal/message/messagedata/consensus_accept.go diff --git a/be1-go/message/messagedata/consensus_elect.go b/be1-go/internal/message/messagedata/consensus_elect.go similarity index 100% rename from be1-go/message/messagedata/consensus_elect.go rename to be1-go/internal/message/messagedata/consensus_elect.go diff --git a/be1-go/message/messagedata/consensus_elect_accept.go b/be1-go/internal/message/messagedata/consensus_elect_accept.go similarity index 100% rename from be1-go/message/messagedata/consensus_elect_accept.go rename to be1-go/internal/message/messagedata/consensus_elect_accept.go diff --git a/be1-go/message/messagedata/consensus_failure.go b/be1-go/internal/message/messagedata/consensus_failure.go similarity index 100% rename from be1-go/message/messagedata/consensus_failure.go rename to be1-go/internal/message/messagedata/consensus_failure.go diff --git a/be1-go/message/messagedata/consensus_learn.go b/be1-go/internal/message/messagedata/consensus_learn.go similarity index 100% rename from be1-go/message/messagedata/consensus_learn.go rename to be1-go/internal/message/messagedata/consensus_learn.go diff --git a/be1-go/message/messagedata/consensus_prepare.go b/be1-go/internal/message/messagedata/consensus_prepare.go similarity index 100% rename from be1-go/message/messagedata/consensus_prepare.go rename to be1-go/internal/message/messagedata/consensus_prepare.go diff --git a/be1-go/message/messagedata/consensus_promise.go b/be1-go/internal/message/messagedata/consensus_promise.go similarity index 100% rename from be1-go/message/messagedata/consensus_promise.go rename to be1-go/internal/message/messagedata/consensus_promise.go diff --git a/be1-go/message/messagedata/consensus_propose.go b/be1-go/internal/message/messagedata/consensus_propose.go similarity index 100% rename from be1-go/message/messagedata/consensus_propose.go rename to be1-go/internal/message/messagedata/consensus_propose.go diff --git a/be1-go/message/messagedata/election_end.go b/be1-go/internal/message/messagedata/election_end.go similarity index 98% rename from be1-go/message/messagedata/election_end.go rename to be1-go/internal/message/messagedata/election_end.go index 54fcf3b786..6906d075c2 100644 --- a/be1-go/message/messagedata/election_end.go +++ b/be1-go/internal/message/messagedata/election_end.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strings" ) diff --git a/be1-go/message/messagedata/election_key.go b/be1-go/internal/message/messagedata/election_key.go similarity index 100% rename from be1-go/message/messagedata/election_key.go rename to be1-go/internal/message/messagedata/election_key.go diff --git a/be1-go/message/messagedata/election_open.go b/be1-go/internal/message/messagedata/election_open.go similarity index 98% rename from be1-go/message/messagedata/election_open.go rename to be1-go/internal/message/messagedata/election_open.go index de3874586c..d5641ae4e7 100644 --- a/be1-go/message/messagedata/election_open.go +++ b/be1-go/internal/message/messagedata/election_open.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strings" ) diff --git a/be1-go/message/messagedata/election_result.go b/be1-go/internal/message/messagedata/election_result.go similarity index 100% rename from be1-go/message/messagedata/election_result.go rename to be1-go/internal/message/messagedata/election_result.go diff --git a/be1-go/message/messagedata/election_setup.go b/be1-go/internal/message/messagedata/election_setup.go similarity index 99% rename from be1-go/message/messagedata/election_setup.go rename to be1-go/internal/message/messagedata/election_setup.go index e81fc1ef23..60b6a301fc 100644 --- a/be1-go/message/messagedata/election_setup.go +++ b/be1-go/internal/message/messagedata/election_setup.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strconv" ) diff --git a/be1-go/message/messagedata/federation_challenge.go b/be1-go/internal/message/messagedata/federation_challenge.go similarity index 97% rename from be1-go/message/messagedata/federation_challenge.go rename to be1-go/internal/message/messagedata/federation_challenge.go index 4d0c60d8be..50aa5a3474 100644 --- a/be1-go/message/messagedata/federation_challenge.go +++ b/be1-go/internal/message/messagedata/federation_challenge.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/hex" - "popstellar/message/answer" + "popstellar/internal/message/answer" ) // FederationChallenge defines a message data diff --git a/be1-go/message/messagedata/federation_expect.go b/be1-go/internal/message/messagedata/federation_expect.go similarity index 92% rename from be1-go/message/messagedata/federation_expect.go rename to be1-go/internal/message/messagedata/federation_expect.go index 7e909c62f3..6b55d2ff1e 100644 --- a/be1-go/message/messagedata/federation_expect.go +++ b/be1-go/internal/message/messagedata/federation_expect.go @@ -1,6 +1,6 @@ package messagedata -import "popstellar/message/query/method/message" +import "popstellar/internal/message/query/method/message" // FederationExpect defines a message data type FederationExpect struct { diff --git a/be1-go/message/messagedata/federation_init.go b/be1-go/internal/message/messagedata/federation_init.go similarity index 92% rename from be1-go/message/messagedata/federation_init.go rename to be1-go/internal/message/messagedata/federation_init.go index 3e013fc6db..f6e640e3e4 100644 --- a/be1-go/message/messagedata/federation_init.go +++ b/be1-go/internal/message/messagedata/federation_init.go @@ -1,6 +1,6 @@ package messagedata -import "popstellar/message/query/method/message" +import "popstellar/internal/message/query/method/message" // FederationInit defines a message data type FederationInit struct { diff --git a/be1-go/message/messagedata/federation_request_challenge.go b/be1-go/internal/message/messagedata/federation_request_challenge.go similarity index 100% rename from be1-go/message/messagedata/federation_request_challenge.go rename to be1-go/internal/message/messagedata/federation_request_challenge.go diff --git a/be1-go/message/messagedata/federation_result.go b/be1-go/internal/message/messagedata/federation_result.go similarity index 92% rename from be1-go/message/messagedata/federation_result.go rename to be1-go/internal/message/messagedata/federation_result.go index 88a5987678..7661d8db99 100644 --- a/be1-go/message/messagedata/federation_result.go +++ b/be1-go/internal/message/messagedata/federation_result.go @@ -1,6 +1,6 @@ package messagedata -import "popstellar/message/query/method/message" +import "popstellar/internal/message/query/method/message" // FederationResult defines a message data type FederationResult struct { diff --git a/be1-go/message/messagedata/lao_create.go b/be1-go/internal/message/messagedata/lao_create.go similarity index 98% rename from be1-go/message/messagedata/lao_create.go rename to be1-go/internal/message/messagedata/lao_create.go index 159e8d8d22..12878450ae 100644 --- a/be1-go/message/messagedata/lao_create.go +++ b/be1-go/internal/message/messagedata/lao_create.go @@ -3,7 +3,7 @@ package messagedata import ( "encoding/base64" "fmt" - "popstellar/message/answer" + "popstellar/internal/message/answer" ) // LaoCreate defines a message data diff --git a/be1-go/message/messagedata/lao_greet.go b/be1-go/internal/message/messagedata/lao_greet.go similarity index 100% rename from be1-go/message/messagedata/lao_greet.go rename to be1-go/internal/message/messagedata/lao_greet.go diff --git a/be1-go/message/messagedata/lao_state.go b/be1-go/internal/message/messagedata/lao_state.go similarity index 100% rename from be1-go/message/messagedata/lao_state.go rename to be1-go/internal/message/messagedata/lao_state.go diff --git a/be1-go/message/messagedata/lao_update.go b/be1-go/internal/message/messagedata/lao_update.go similarity index 100% rename from be1-go/message/messagedata/lao_update.go rename to be1-go/internal/message/messagedata/lao_update.go diff --git a/be1-go/message/messagedata/meeting_create.go b/be1-go/internal/message/messagedata/meeting_create.go similarity index 100% rename from be1-go/message/messagedata/meeting_create.go rename to be1-go/internal/message/messagedata/meeting_create.go diff --git a/be1-go/message/messagedata/meeting_state.go b/be1-go/internal/message/messagedata/meeting_state.go similarity index 100% rename from be1-go/message/messagedata/meeting_state.go rename to be1-go/internal/message/messagedata/meeting_state.go diff --git a/be1-go/message/messagedata/message_witness.go b/be1-go/internal/message/messagedata/message_witness.go similarity index 100% rename from be1-go/message/messagedata/message_witness.go rename to be1-go/internal/message/messagedata/message_witness.go diff --git a/be1-go/message/messagedata/mod.go b/be1-go/internal/message/messagedata/mod.go similarity index 100% rename from be1-go/message/messagedata/mod.go rename to be1-go/internal/message/messagedata/mod.go diff --git a/be1-go/message/messagedata/reaction_add.go b/be1-go/internal/message/messagedata/reaction_add.go similarity index 100% rename from be1-go/message/messagedata/reaction_add.go rename to be1-go/internal/message/messagedata/reaction_add.go diff --git a/be1-go/message/messagedata/reaction_delete.go b/be1-go/internal/message/messagedata/reaction_delete.go similarity index 100% rename from be1-go/message/messagedata/reaction_delete.go rename to be1-go/internal/message/messagedata/reaction_delete.go diff --git a/be1-go/message/messagedata/roll_call_close.go b/be1-go/internal/message/messagedata/roll_call_close.go similarity index 97% rename from be1-go/message/messagedata/roll_call_close.go rename to be1-go/internal/message/messagedata/roll_call_close.go index 42fcc5d451..199947c531 100644 --- a/be1-go/message/messagedata/roll_call_close.go +++ b/be1-go/internal/message/messagedata/roll_call_close.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strconv" "strings" ) diff --git a/be1-go/message/messagedata/roll_call_create.go b/be1-go/internal/message/messagedata/roll_call_create.go similarity index 98% rename from be1-go/message/messagedata/roll_call_create.go rename to be1-go/internal/message/messagedata/roll_call_create.go index d02947f140..d89f679c87 100644 --- a/be1-go/message/messagedata/roll_call_create.go +++ b/be1-go/internal/message/messagedata/roll_call_create.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strconv" "strings" ) diff --git a/be1-go/message/messagedata/roll_call_open.go b/be1-go/internal/message/messagedata/roll_call_open.go similarity index 97% rename from be1-go/message/messagedata/roll_call_open.go rename to be1-go/internal/message/messagedata/roll_call_open.go index 2fc620c8f0..2dcbd73bee 100644 --- a/be1-go/message/messagedata/roll_call_open.go +++ b/be1-go/internal/message/messagedata/roll_call_open.go @@ -2,7 +2,7 @@ package messagedata import ( "encoding/base64" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strconv" "strings" ) diff --git a/be1-go/message/messagedata/roll_call_reopen.go b/be1-go/internal/message/messagedata/roll_call_reopen.go similarity index 100% rename from be1-go/message/messagedata/roll_call_reopen.go rename to be1-go/internal/message/messagedata/roll_call_reopen.go diff --git a/be1-go/message/messagedata/vote_cast_vote.go b/be1-go/internal/message/messagedata/vote_cast_vote.go similarity index 98% rename from be1-go/message/messagedata/vote_cast_vote.go rename to be1-go/internal/message/messagedata/vote_cast_vote.go index 8b8df771bc..f9abbc8d08 100644 --- a/be1-go/message/messagedata/vote_cast_vote.go +++ b/be1-go/internal/message/messagedata/vote_cast_vote.go @@ -3,7 +3,7 @@ package messagedata import ( "encoding/base64" "encoding/json" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strings" ) diff --git a/be1-go/message/messagedata/vote_cast_write_in.go b/be1-go/internal/message/messagedata/vote_cast_write_in.go similarity index 100% rename from be1-go/message/messagedata/vote_cast_write_in.go rename to be1-go/internal/message/messagedata/vote_cast_write_in.go diff --git a/be1-go/message/query/method/broadcast.go b/be1-go/internal/message/query/method/broadcast.go similarity index 75% rename from be1-go/message/query/method/broadcast.go rename to be1-go/internal/message/query/method/broadcast.go index 75b3dd917c..b928b043a2 100644 --- a/be1-go/message/query/method/broadcast.go +++ b/be1-go/internal/message/query/method/broadcast.go @@ -1,8 +1,8 @@ package method import ( - "popstellar/message/query" - "popstellar/message/query/method/message" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method/message" ) // Broadcast defines a JSON RPC broadcast message diff --git a/be1-go/message/query/method/catchup.go b/be1-go/internal/message/query/method/catchup.go similarity index 83% rename from be1-go/message/query/method/catchup.go rename to be1-go/internal/message/query/method/catchup.go index 008bc8282f..7c47f63f74 100644 --- a/be1-go/message/query/method/catchup.go +++ b/be1-go/internal/message/query/method/catchup.go @@ -1,6 +1,6 @@ package method -import "popstellar/message/query" +import "popstellar/internal/message/query" // Catchup define a JSON RPC catchup message type Catchup struct { diff --git a/be1-go/message/query/method/get_messages_by_id.go b/be1-go/internal/message/query/method/get_messages_by_id.go similarity index 84% rename from be1-go/message/query/method/get_messages_by_id.go rename to be1-go/internal/message/query/method/get_messages_by_id.go index 549c98e86a..767db31b9a 100644 --- a/be1-go/message/query/method/get_messages_by_id.go +++ b/be1-go/internal/message/query/method/get_messages_by_id.go @@ -1,7 +1,7 @@ package method import ( - "popstellar/message/query" + "popstellar/internal/message/query" ) // GetMessagesById defines a JSON RPC getMessagesById message diff --git a/be1-go/message/query/method/greet_server.go b/be1-go/internal/message/query/method/greet_server.go similarity index 88% rename from be1-go/message/query/method/greet_server.go rename to be1-go/internal/message/query/method/greet_server.go index 7fdcab7434..406e49b9f4 100644 --- a/be1-go/message/query/method/greet_server.go +++ b/be1-go/internal/message/query/method/greet_server.go @@ -1,6 +1,6 @@ package method -import "popstellar/message/query" +import "popstellar/internal/message/query" type GreetServerParams struct { PublicKey string `json:"public_key"` diff --git a/be1-go/message/query/method/heartbeat.go b/be1-go/internal/message/query/method/heartbeat.go similarity index 81% rename from be1-go/message/query/method/heartbeat.go rename to be1-go/internal/message/query/method/heartbeat.go index 3238fc9992..50052a79c6 100644 --- a/be1-go/message/query/method/heartbeat.go +++ b/be1-go/internal/message/query/method/heartbeat.go @@ -1,7 +1,7 @@ package method import ( - "popstellar/message/query" + "popstellar/internal/message/query" ) // Heartbeat defines a JSON RPC heartbeat message diff --git a/be1-go/message/query/method/message/message.go b/be1-go/internal/message/query/method/message/message.go similarity index 98% rename from be1-go/message/query/method/message/message.go rename to be1-go/internal/message/query/method/message/message.go index f283a18798..04d2c366bb 100644 --- a/be1-go/message/query/method/message/message.go +++ b/be1-go/internal/message/query/method/message/message.go @@ -3,7 +3,7 @@ package message import ( "encoding/base64" "encoding/json" - "popstellar/message/answer" + "popstellar/internal/message/answer" ) // Message defines a JSON RPC message diff --git a/be1-go/message/query/method/publish.go b/be1-go/internal/message/query/method/publish.go similarity index 76% rename from be1-go/message/query/method/publish.go rename to be1-go/internal/message/query/method/publish.go index 0a0651ede7..fa3b5d08c1 100644 --- a/be1-go/message/query/method/publish.go +++ b/be1-go/internal/message/query/method/publish.go @@ -1,8 +1,8 @@ package method import ( - "popstellar/message/query" - "popstellar/message/query/method/message" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method/message" ) // Publish defines a JSON RPC publish message diff --git a/be1-go/message/query/method/rumor.go b/be1-go/internal/message/query/method/rumor.go similarity index 80% rename from be1-go/message/query/method/rumor.go rename to be1-go/internal/message/query/method/rumor.go index fa39c852aa..566a380a04 100644 --- a/be1-go/message/query/method/rumor.go +++ b/be1-go/internal/message/query/method/rumor.go @@ -1,8 +1,8 @@ package method import ( - "popstellar/message/query" - "popstellar/message/query/method/message" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method/message" ) type ParamsRumor struct { diff --git a/be1-go/message/query/method/subscribe.go b/be1-go/internal/message/query/method/subscribe.go similarity index 84% rename from be1-go/message/query/method/subscribe.go rename to be1-go/internal/message/query/method/subscribe.go index e4e4ad0d3d..7df47c83e8 100644 --- a/be1-go/message/query/method/subscribe.go +++ b/be1-go/internal/message/query/method/subscribe.go @@ -1,6 +1,6 @@ package method -import "popstellar/message/query" +import "popstellar/internal/message/query" // Subscribe defines a JSON RPC subscribe message type Subscribe struct { diff --git a/be1-go/message/query/method/unsubscribe.go b/be1-go/internal/message/query/method/unsubscribe.go similarity index 84% rename from be1-go/message/query/method/unsubscribe.go rename to be1-go/internal/message/query/method/unsubscribe.go index 0c74d00e96..45edb59c25 100644 --- a/be1-go/message/query/method/unsubscribe.go +++ b/be1-go/internal/message/query/method/unsubscribe.go @@ -1,6 +1,6 @@ package method -import "popstellar/message/query" +import "popstellar/internal/message/query" // Unsubscribe defines a JSON RPC unsubscribe message type Unsubscribe struct { diff --git a/be1-go/message/query/query.go b/be1-go/internal/message/query/query.go similarity index 91% rename from be1-go/message/query/query.go rename to be1-go/internal/message/query/query.go index d499859c88..c3ed3f2ddf 100644 --- a/be1-go/message/query/query.go +++ b/be1-go/internal/message/query/query.go @@ -1,6 +1,6 @@ package query -import message "popstellar/message" +import message "popstellar/internal/message" const ( MethodPublish = "publish" diff --git a/be1-go/message/test/answer/answer_test.go b/be1-go/internal/message/test/answer/answer_test.go similarity index 96% rename from be1-go/message/test/answer/answer_test.go rename to be1-go/internal/message/test/answer/answer_test.go index 0114af314f..3884dfea00 100644 --- a/be1-go/message/test/answer/answer_test.go +++ b/be1-go/internal/message/test/answer/answer_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - message "popstellar/message" - "popstellar/message/answer" + message "popstellar/internal/message" + "popstellar/internal/message/answer" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/answer/error_test.go b/be1-go/internal/message/test/answer/error_test.go similarity index 87% rename from be1-go/message/test/answer/error_test.go rename to be1-go/internal/message/test/answer/error_test.go index ca861dda9b..48c8dfcef6 100644 --- a/be1-go/message/test/answer/error_test.go +++ b/be1-go/internal/message/test/answer/error_test.go @@ -1,7 +1,7 @@ package answer import ( - "popstellar/message/answer" + "popstellar/internal/message/answer" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/answer/mod.go b/be1-go/internal/message/test/answer/mod.go similarity index 58% rename from be1-go/message/test/answer/mod.go rename to be1-go/internal/message/test/answer/mod.go index 3d77a57662..dd7bb42222 100644 --- a/be1-go/message/test/answer/mod.go +++ b/be1-go/internal/message/test/answer/mod.go @@ -5,6 +5,6 @@ import "path/filepath" var relativeExamplePath string func init() { - relativeExamplePath = filepath.Join("..", "..", "..", "..", "protocol", + relativeExamplePath = filepath.Join("..", "..", "..", "..", "..", "protocol", "examples", "answer") } diff --git a/be1-go/message/test/message_test.go b/be1-go/internal/message/test/message_test.go similarity index 87% rename from be1-go/message/test/message_test.go rename to be1-go/internal/message/test/message_test.go index be13e1d173..0afce73e31 100644 --- a/be1-go/message/test/message_test.go +++ b/be1-go/internal/message/test/message_test.go @@ -4,15 +4,15 @@ import ( "encoding/base64" "os" "path/filepath" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" "github.com/stretchr/testify/require" ) func Test_UnmarshalData(t *testing.T) { - messageDataPath := filepath.Join("..", "..", "..", "protocol", + messageDataPath := filepath.Join("..", "..", "..", "..", "protocol", "examples", "messageData", "lao_create", "lao_create.json") messageDataBuf, err := os.ReadFile(messageDataPath) diff --git a/be1-go/message/test/messagedata/authenticate_user_test.go b/be1-go/internal/message/test/messagedata/authenticate_user_test.go similarity index 97% rename from be1-go/message/test/messagedata/authenticate_user_test.go rename to be1-go/internal/message/test/messagedata/authenticate_user_test.go index 777b8825c4..1aa3540792 100644 --- a/be1-go/message/test/messagedata/authenticate_user_test.go +++ b/be1-go/internal/message/test/messagedata/authenticate_user_test.go @@ -5,7 +5,7 @@ import ( "github.com/stretchr/testify/require" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" ) diff --git a/be1-go/message/test/messagedata/chirp_add_test.go b/be1-go/internal/message/test/messagedata/chirp_add_test.go similarity index 97% rename from be1-go/message/test/messagedata/chirp_add_test.go rename to be1-go/internal/message/test/messagedata/chirp_add_test.go index a6273ead5e..7d54214b94 100644 --- a/be1-go/message/test/messagedata/chirp_add_test.go +++ b/be1-go/internal/message/test/messagedata/chirp_add_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/chirp_broadcast_test.go b/be1-go/internal/message/test/messagedata/chirp_broadcast_test.go similarity index 96% rename from be1-go/message/test/messagedata/chirp_broadcast_test.go rename to be1-go/internal/message/test/messagedata/chirp_broadcast_test.go index 49b5b6b0e6..1b0b61bd3b 100644 --- a/be1-go/message/test/messagedata/chirp_broadcast_test.go +++ b/be1-go/internal/message/test/messagedata/chirp_broadcast_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/chirp_delete_test.go b/be1-go/internal/message/test/messagedata/chirp_delete_test.go similarity index 97% rename from be1-go/message/test/messagedata/chirp_delete_test.go rename to be1-go/internal/message/test/messagedata/chirp_delete_test.go index 95afdf5cd6..57be8f303c 100644 --- a/be1-go/message/test/messagedata/chirp_delete_test.go +++ b/be1-go/internal/message/test/messagedata/chirp_delete_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/chirp_notify_add_test.go b/be1-go/internal/message/test/messagedata/chirp_notify_add_test.go similarity index 97% rename from be1-go/message/test/messagedata/chirp_notify_add_test.go rename to be1-go/internal/message/test/messagedata/chirp_notify_add_test.go index b7d5711aee..aac6ae0739 100644 --- a/be1-go/message/test/messagedata/chirp_notify_add_test.go +++ b/be1-go/internal/message/test/messagedata/chirp_notify_add_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/chirp_notify_delete_test.go b/be1-go/internal/message/test/messagedata/chirp_notify_delete_test.go similarity index 97% rename from be1-go/message/test/messagedata/chirp_notify_delete_test.go rename to be1-go/internal/message/test/messagedata/chirp_notify_delete_test.go index 790eb97c6c..b2609aaf81 100644 --- a/be1-go/message/test/messagedata/chirp_notify_delete_test.go +++ b/be1-go/internal/message/test/messagedata/chirp_notify_delete_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/coin_post_transaction_test.go b/be1-go/internal/message/test/messagedata/coin_post_transaction_test.go similarity index 98% rename from be1-go/message/test/messagedata/coin_post_transaction_test.go rename to be1-go/internal/message/test/messagedata/coin_post_transaction_test.go index cd3056a763..5bcbb9b308 100644 --- a/be1-go/message/test/messagedata/coin_post_transaction_test.go +++ b/be1-go/internal/message/test/messagedata/coin_post_transaction_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_accept_test.go b/be1-go/internal/message/test/messagedata/consensus_accept_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_accept_test.go rename to be1-go/internal/message/test/messagedata/consensus_accept_test.go index 1c592d8c56..97efa8ae15 100644 --- a/be1-go/message/test/messagedata/consensus_accept_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_accept_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_elect_accept_test.go b/be1-go/internal/message/test/messagedata/consensus_elect_accept_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_elect_accept_test.go rename to be1-go/internal/message/test/messagedata/consensus_elect_accept_test.go index aa3e88b6f7..1f6d6f0193 100644 --- a/be1-go/message/test/messagedata/consensus_elect_accept_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_elect_accept_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_elect_test.go b/be1-go/internal/message/test/messagedata/consensus_elect_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_elect_test.go rename to be1-go/internal/message/test/messagedata/consensus_elect_test.go index 344b38edbf..a0df171292 100644 --- a/be1-go/message/test/messagedata/consensus_elect_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_elect_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_failure_test.go b/be1-go/internal/message/test/messagedata/consensus_failure_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_failure_test.go rename to be1-go/internal/message/test/messagedata/consensus_failure_test.go index a2c256cfdd..cf97d2527c 100644 --- a/be1-go/message/test/messagedata/consensus_failure_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_failure_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_learn_test.go b/be1-go/internal/message/test/messagedata/consensus_learn_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_learn_test.go rename to be1-go/internal/message/test/messagedata/consensus_learn_test.go index bda420d9e1..ba9e2dba98 100644 --- a/be1-go/message/test/messagedata/consensus_learn_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_learn_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_prepare_test.go b/be1-go/internal/message/test/messagedata/consensus_prepare_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_prepare_test.go rename to be1-go/internal/message/test/messagedata/consensus_prepare_test.go index 29a91341ab..079616f879 100644 --- a/be1-go/message/test/messagedata/consensus_prepare_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_prepare_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_promise_test.go b/be1-go/internal/message/test/messagedata/consensus_promise_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_promise_test.go rename to be1-go/internal/message/test/messagedata/consensus_promise_test.go index 40bf1f6991..5613d2028d 100644 --- a/be1-go/message/test/messagedata/consensus_promise_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_promise_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/consensus_propose_test.go b/be1-go/internal/message/test/messagedata/consensus_propose_test.go similarity index 98% rename from be1-go/message/test/messagedata/consensus_propose_test.go rename to be1-go/internal/message/test/messagedata/consensus_propose_test.go index 1da4f1dab7..1d9b7b6f0e 100644 --- a/be1-go/message/test/messagedata/consensus_propose_test.go +++ b/be1-go/internal/message/test/messagedata/consensus_propose_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/election_end_test.go b/be1-go/internal/message/test/messagedata/election_end_test.go similarity index 96% rename from be1-go/message/test/messagedata/election_end_test.go rename to be1-go/internal/message/test/messagedata/election_end_test.go index 05108a081f..6d119f22bb 100644 --- a/be1-go/message/test/messagedata/election_end_test.go +++ b/be1-go/internal/message/test/messagedata/election_end_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/election_key_test.go b/be1-go/internal/message/test/messagedata/election_key_test.go similarity index 95% rename from be1-go/message/test/messagedata/election_key_test.go rename to be1-go/internal/message/test/messagedata/election_key_test.go index d177745e77..da3cee3f65 100644 --- a/be1-go/message/test/messagedata/election_key_test.go +++ b/be1-go/internal/message/test/messagedata/election_key_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/election_open_test.go b/be1-go/internal/message/test/messagedata/election_open_test.go similarity index 96% rename from be1-go/message/test/messagedata/election_open_test.go rename to be1-go/internal/message/test/messagedata/election_open_test.go index 97eaf21ece..0749d03b28 100644 --- a/be1-go/message/test/messagedata/election_open_test.go +++ b/be1-go/internal/message/test/messagedata/election_open_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/election_result_test.go b/be1-go/internal/message/test/messagedata/election_result_test.go similarity index 96% rename from be1-go/message/test/messagedata/election_result_test.go rename to be1-go/internal/message/test/messagedata/election_result_test.go index 642d272ca9..ab98f637ef 100644 --- a/be1-go/message/test/messagedata/election_result_test.go +++ b/be1-go/internal/message/test/messagedata/election_result_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/election_setup_test.go b/be1-go/internal/message/test/messagedata/election_setup_test.go similarity index 97% rename from be1-go/message/test/messagedata/election_setup_test.go rename to be1-go/internal/message/test/messagedata/election_setup_test.go index 7cd4b4de34..b94f24a37a 100644 --- a/be1-go/message/test/messagedata/election_setup_test.go +++ b/be1-go/internal/message/test/messagedata/election_setup_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/lao_create_test.go b/be1-go/internal/message/test/messagedata/lao_create_test.go similarity index 98% rename from be1-go/message/test/messagedata/lao_create_test.go rename to be1-go/internal/message/test/messagedata/lao_create_test.go index 35b52691b2..e3ae475c16 100644 --- a/be1-go/message/test/messagedata/lao_create_test.go +++ b/be1-go/internal/message/test/messagedata/lao_create_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/lao_greet_test.go b/be1-go/internal/message/test/messagedata/lao_greet_test.go similarity index 97% rename from be1-go/message/test/messagedata/lao_greet_test.go rename to be1-go/internal/message/test/messagedata/lao_greet_test.go index d8b2ff7d74..ae249163ae 100644 --- a/be1-go/message/test/messagedata/lao_greet_test.go +++ b/be1-go/internal/message/test/messagedata/lao_greet_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/lao_state_test.go b/be1-go/internal/message/test/messagedata/lao_state_test.go similarity index 97% rename from be1-go/message/test/messagedata/lao_state_test.go rename to be1-go/internal/message/test/messagedata/lao_state_test.go index f6cf62b393..df4fc07934 100644 --- a/be1-go/message/test/messagedata/lao_state_test.go +++ b/be1-go/internal/message/test/messagedata/lao_state_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/lao_update_test.go b/be1-go/internal/message/test/messagedata/lao_update_test.go similarity index 98% rename from be1-go/message/test/messagedata/lao_update_test.go rename to be1-go/internal/message/test/messagedata/lao_update_test.go index e21f7ab703..16e6c8a8c1 100644 --- a/be1-go/message/test/messagedata/lao_update_test.go +++ b/be1-go/internal/message/test/messagedata/lao_update_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/meeting_create_test.go b/be1-go/internal/message/test/messagedata/meeting_create_test.go similarity index 96% rename from be1-go/message/test/messagedata/meeting_create_test.go rename to be1-go/internal/message/test/messagedata/meeting_create_test.go index c7ca844042..9fe6aacb4e 100644 --- a/be1-go/message/test/messagedata/meeting_create_test.go +++ b/be1-go/internal/message/test/messagedata/meeting_create_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/meeting_state_test.go b/be1-go/internal/message/test/messagedata/meeting_state_test.go similarity index 97% rename from be1-go/message/test/messagedata/meeting_state_test.go rename to be1-go/internal/message/test/messagedata/meeting_state_test.go index 61947db665..4180381e3b 100644 --- a/be1-go/message/test/messagedata/meeting_state_test.go +++ b/be1-go/internal/message/test/messagedata/meeting_state_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/message_witness_test.go b/be1-go/internal/message/test/messagedata/message_witness_test.go similarity index 96% rename from be1-go/message/test/messagedata/message_witness_test.go rename to be1-go/internal/message/test/messagedata/message_witness_test.go index f1c99e7e98..791b8fa998 100644 --- a/be1-go/message/test/messagedata/message_witness_test.go +++ b/be1-go/internal/message/test/messagedata/message_witness_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/mod_test.go b/be1-go/internal/message/test/messagedata/mod_test.go similarity index 94% rename from be1-go/message/test/messagedata/mod_test.go rename to be1-go/internal/message/test/messagedata/mod_test.go index 4df144a7b7..79dd6f6971 100644 --- a/be1-go/message/test/messagedata/mod_test.go +++ b/be1-go/internal/message/test/messagedata/mod_test.go @@ -3,7 +3,7 @@ package messagedata import ( "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" @@ -12,7 +12,7 @@ import ( var relativeExamplePath string func init() { - relativeExamplePath = filepath.Join("..", "..", "..", "..", "protocol", + relativeExamplePath = filepath.Join("..", "..", "..", "..", "..", "protocol", "examples", "messageData") } diff --git a/be1-go/message/test/messagedata/reaction_add_test.go b/be1-go/internal/message/test/messagedata/reaction_add_test.go similarity index 97% rename from be1-go/message/test/messagedata/reaction_add_test.go rename to be1-go/internal/message/test/messagedata/reaction_add_test.go index b476f37ac4..446e4eb03e 100644 --- a/be1-go/message/test/messagedata/reaction_add_test.go +++ b/be1-go/internal/message/test/messagedata/reaction_add_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/reaction_delete_test.go b/be1-go/internal/message/test/messagedata/reaction_delete_test.go similarity index 97% rename from be1-go/message/test/messagedata/reaction_delete_test.go rename to be1-go/internal/message/test/messagedata/reaction_delete_test.go index 02ccfc901f..a57d6987b6 100644 --- a/be1-go/message/test/messagedata/reaction_delete_test.go +++ b/be1-go/internal/message/test/messagedata/reaction_delete_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/roll_call_close_test.go b/be1-go/internal/message/test/messagedata/roll_call_close_test.go similarity index 96% rename from be1-go/message/test/messagedata/roll_call_close_test.go rename to be1-go/internal/message/test/messagedata/roll_call_close_test.go index 1683510652..e808a395d8 100644 --- a/be1-go/message/test/messagedata/roll_call_close_test.go +++ b/be1-go/internal/message/test/messagedata/roll_call_close_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/roll_call_create_test.go b/be1-go/internal/message/test/messagedata/roll_call_create_test.go similarity index 96% rename from be1-go/message/test/messagedata/roll_call_create_test.go rename to be1-go/internal/message/test/messagedata/roll_call_create_test.go index 54b2ed5448..08c05bf76a 100644 --- a/be1-go/message/test/messagedata/roll_call_create_test.go +++ b/be1-go/internal/message/test/messagedata/roll_call_create_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/roll_call_open_test.go b/be1-go/internal/message/test/messagedata/roll_call_open_test.go similarity index 96% rename from be1-go/message/test/messagedata/roll_call_open_test.go rename to be1-go/internal/message/test/messagedata/roll_call_open_test.go index 0d40fc5da7..36e94d7377 100644 --- a/be1-go/message/test/messagedata/roll_call_open_test.go +++ b/be1-go/internal/message/test/messagedata/roll_call_open_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/roll_call_reopen_test.go b/be1-go/internal/message/test/messagedata/roll_call_reopen_test.go similarity index 96% rename from be1-go/message/test/messagedata/roll_call_reopen_test.go rename to be1-go/internal/message/test/messagedata/roll_call_reopen_test.go index 3a2a0c02ab..3ba1ed9dc1 100644 --- a/be1-go/message/test/messagedata/roll_call_reopen_test.go +++ b/be1-go/internal/message/test/messagedata/roll_call_reopen_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/messagedata/vote_cast_vote_test.go b/be1-go/internal/message/test/messagedata/vote_cast_vote_test.go similarity index 97% rename from be1-go/message/test/messagedata/vote_cast_vote_test.go rename to be1-go/internal/message/test/messagedata/vote_cast_vote_test.go index 5660546f17..31cc992181 100644 --- a/be1-go/message/test/messagedata/vote_cast_vote_test.go +++ b/be1-go/internal/message/test/messagedata/vote_cast_vote_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/mod.go b/be1-go/internal/message/test/mod.go similarity index 100% rename from be1-go/message/test/mod.go rename to be1-go/internal/message/test/mod.go diff --git a/be1-go/message/test/query/method/broadcast_test.go b/be1-go/internal/message/test/query/method/broadcast_test.go similarity index 91% rename from be1-go/message/test/query/method/broadcast_test.go rename to be1-go/internal/message/test/query/method/broadcast_test.go index 31d437c846..5dad024896 100644 --- a/be1-go/message/test/query/method/broadcast_test.go +++ b/be1-go/internal/message/test/query/method/broadcast_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/catchup_test.go b/be1-go/internal/message/test/query/method/catchup_test.go similarity index 91% rename from be1-go/message/test/query/method/catchup_test.go rename to be1-go/internal/message/test/query/method/catchup_test.go index 7b641a466c..4a9bc4dcb8 100644 --- a/be1-go/message/test/query/method/catchup_test.go +++ b/be1-go/internal/message/test/query/method/catchup_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/get_messages_by_id_test.go b/be1-go/internal/message/test/query/method/get_messages_by_id_test.go similarity index 95% rename from be1-go/message/test/query/method/get_messages_by_id_test.go rename to be1-go/internal/message/test/query/method/get_messages_by_id_test.go index 725790d92c..76698a12ac 100644 --- a/be1-go/message/test/query/method/get_messages_by_id_test.go +++ b/be1-go/internal/message/test/query/method/get_messages_by_id_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/greet_server_test.go b/be1-go/internal/message/test/query/method/greet_server_test.go similarity index 93% rename from be1-go/message/test/query/method/greet_server_test.go rename to be1-go/internal/message/test/query/method/greet_server_test.go index 5e12f989ab..c423574b42 100644 --- a/be1-go/message/test/query/method/greet_server_test.go +++ b/be1-go/internal/message/test/query/method/greet_server_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" ) diff --git a/be1-go/message/test/query/method/heartbeat_test.go b/be1-go/internal/message/test/query/method/heartbeat_test.go similarity index 94% rename from be1-go/message/test/query/method/heartbeat_test.go rename to be1-go/internal/message/test/query/method/heartbeat_test.go index e50e388f83..bd8c603ad4 100644 --- a/be1-go/message/test/query/method/heartbeat_test.go +++ b/be1-go/internal/message/test/query/method/heartbeat_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/mod.go b/be1-go/internal/message/test/query/method/mod.go similarity index 89% rename from be1-go/message/test/query/method/mod.go rename to be1-go/internal/message/test/query/method/mod.go index 6c7bf3dac7..b1101a6336 100644 --- a/be1-go/message/test/query/method/mod.go +++ b/be1-go/internal/message/test/query/method/mod.go @@ -5,6 +5,6 @@ import "path/filepath" var relativeExamplePath string func init() { - relativeExamplePath = filepath.Join("..", "..", "..", "..", "..", "protocol", + relativeExamplePath = filepath.Join("..", "..", "..", "..", "..", "..", "protocol", "examples", "query") } diff --git a/be1-go/message/test/query/method/publish_test.go b/be1-go/internal/message/test/query/method/publish_test.go similarity index 95% rename from be1-go/message/test/query/method/publish_test.go rename to be1-go/internal/message/test/query/method/publish_test.go index 33da949dcd..41cf74b3ef 100644 --- a/be1-go/message/test/query/method/publish_test.go +++ b/be1-go/internal/message/test/query/method/publish_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/subscribe_test.go b/be1-go/internal/message/test/query/method/subscribe_test.go similarity index 91% rename from be1-go/message/test/query/method/subscribe_test.go rename to be1-go/internal/message/test/query/method/subscribe_test.go index 07006f2989..e83b972bdf 100644 --- a/be1-go/message/test/query/method/subscribe_test.go +++ b/be1-go/internal/message/test/query/method/subscribe_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/message/test/query/method/unsubscribe_test.go b/be1-go/internal/message/test/query/method/unsubscribe_test.go similarity index 91% rename from be1-go/message/test/query/method/unsubscribe_test.go rename to be1-go/internal/message/test/query/method/unsubscribe_test.go index aeb2c0d818..72868ab93a 100644 --- a/be1-go/message/test/query/method/unsubscribe_test.go +++ b/be1-go/internal/message/test/query/method/unsubscribe_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message" - "popstellar/message/query/method" + "popstellar/internal/message" + "popstellar/internal/message/query/method" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/network/network.go b/be1-go/internal/network/network.go similarity index 100% rename from be1-go/network/network.go rename to be1-go/internal/network/network.go diff --git a/be1-go/network/server.go b/be1-go/internal/network/server.go similarity index 96% rename from be1-go/network/server.go rename to be1-go/internal/network/server.go index a55f269c31..bbf661ff21 100644 --- a/be1-go/network/server.go +++ b/be1-go/internal/network/server.go @@ -4,9 +4,9 @@ import ( "context" "fmt" "net/http" - "popstellar" - "popstellar/network/socket" - "popstellar/old/hub" + "popstellar/internal/logger" + "popstellar/internal/network/socket" + "popstellar/internal/old/hub" "sync" "time" @@ -149,8 +149,8 @@ func (s *Server) infoHandler(w http.ResponseWriter, r *http.Request) { "socketType": "%s" }` - resp := fmt.Sprintf(fmtStr, popstellar.Version, popstellar.ShortSHA, - popstellar.BuildTime, s.st) + resp := fmt.Sprintf(fmtStr, logger.Version, logger.ShortSHA, + logger.BuildTime, s.st) w.Write([]byte(resp)) } diff --git a/be1-go/network/server_test.go b/be1-go/internal/network/server_test.go similarity index 90% rename from be1-go/network/server_test.go rename to be1-go/internal/network/server_test.go index d6db745542..17e87948a0 100644 --- a/be1-go/network/server_test.go +++ b/be1-go/internal/network/server_test.go @@ -4,9 +4,9 @@ import ( "io" "net/http" "net/http/httptest" - "popstellar/crypto" - "popstellar/old/hub" - "popstellar/old/hub/standard_hub" + "popstellar/internal/crypto" + "popstellar/internal/old/hub" + "popstellar/internal/old/hub/standard_hub" "testing" "github.com/rs/zerolog" diff --git a/be1-go/network/shutdown.go b/be1-go/internal/network/shutdown.go similarity index 96% rename from be1-go/network/shutdown.go rename to be1-go/internal/network/shutdown.go index 2ccc080b2e..fdf84ab0f5 100644 --- a/be1-go/network/shutdown.go +++ b/be1-go/internal/network/shutdown.go @@ -4,7 +4,7 @@ import ( "context" "os" "os/signal" - "popstellar/popcha" + "popstellar/internal/popcha" "syscall" ) diff --git a/be1-go/network/socket/fake_socket.go b/be1-go/internal/network/socket/fake_socket.go similarity index 93% rename from be1-go/network/socket/fake_socket.go rename to be1-go/internal/network/socket/fake_socket.go index f8dc5d4cef..a363d442a0 100644 --- a/be1-go/network/socket/fake_socket.go +++ b/be1-go/internal/network/socket/fake_socket.go @@ -1,6 +1,6 @@ package socket -import "popstellar/message/query/method/message" +import "popstellar/internal/message/query/method/message" // FakeSocket is a fake implementation of a Socket // diff --git a/be1-go/network/socket/socket.go b/be1-go/internal/network/socket/socket.go similarity index 97% rename from be1-go/network/socket/socket.go rename to be1-go/internal/network/socket/socket.go index 83a1b35324..de6a8d6f5b 100644 --- a/be1-go/network/socket/socket.go +++ b/be1-go/internal/network/socket/socket.go @@ -7,7 +7,7 @@ package socket import ( - "popstellar/message/query/method/message" + "popstellar/internal/message/query/method/message" "time" ) diff --git a/be1-go/network/socket/socket_impl.go b/be1-go/internal/network/socket/socket_impl.go similarity index 98% rename from be1-go/network/socket/socket_impl.go rename to be1-go/internal/network/socket/socket_impl.go index ace6b8460c..1edb45b491 100644 --- a/be1-go/network/socket/socket_impl.go +++ b/be1-go/internal/network/socket/socket_impl.go @@ -3,9 +3,9 @@ package socket import ( "encoding/json" "errors" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/query/method/message" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method/message" "sync" "time" diff --git a/be1-go/network/socket/socket_impl_test.go b/be1-go/internal/network/socket/socket_impl_test.go similarity index 96% rename from be1-go/network/socket/socket_impl_test.go rename to be1-go/internal/network/socket/socket_impl_test.go index 5b7830716d..07f3a9fed0 100644 --- a/be1-go/network/socket/socket_impl_test.go +++ b/be1-go/internal/network/socket/socket_impl_test.go @@ -6,8 +6,8 @@ import ( "github.com/rs/zerolog" "github.com/stretchr/testify/require" "os" - "popstellar/message/answer" - "popstellar/message/query/method/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method/message" "sync" "testing" ) diff --git a/be1-go/old/channel/authentication/authentication.go b/be1-go/internal/old/channel/authentication/authentication.go similarity index 97% rename from be1-go/old/channel/authentication/authentication.go rename to be1-go/internal/old/channel/authentication/authentication.go index 0f70c8fce4..b8f75fcaeb 100644 --- a/be1-go/old/channel/authentication/authentication.go +++ b/be1-go/internal/old/channel/authentication/authentication.go @@ -9,16 +9,16 @@ import ( "golang.org/x/xerrors" "net/url" "os" - "popstellar/crypto" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "strings" "sync" diff --git a/be1-go/old/channel/authentication/authentication_test.go b/be1-go/internal/old/channel/authentication/authentication_test.go similarity index 94% rename from be1-go/old/channel/authentication/authentication_test.go rename to be1-go/internal/old/channel/authentication/authentication_test.go index 5768234bf2..d12fcd82f6 100644 --- a/be1-go/old/channel/authentication/authentication_test.go +++ b/be1-go/internal/old/channel/authentication/authentication_test.go @@ -18,22 +18,22 @@ import ( "net/http" "os" "path/filepath" - "popstellar" - "popstellar/crypto" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + "popstellar/internal/logger" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" ) const ( - relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" - relativeQueryExamplePath string = "../../../../protocol/examples/query" + relativeMsgDataExamplePath string = "../../../validation/protocol/examples/messageData" + relativeQueryExamplePath string = "../../../validation/protocol/examples/query" secPathTest = "../../../crypto/popcha.rsa" pubPathtest = "../../../crypto/popcha.rsa.pub" ) @@ -103,7 +103,7 @@ func Test_Authenticate_User(t *testing.T) { require.NoError(t, err) name := "3hfd5xSty1VShCdcfLUDsgNF_EnMSRiFk74xvH5LRjM=/authenticate" // Create the channel - authCha := NewChannel("3hfd5xSty1VShCdcfLUDsgNF_EnMSRiFk74xvH5LRjM=/authenticate", fakeHub, popstellar.Logger, secPathTest, pubPathtest) + authCha := NewChannel("3hfd5xSty1VShCdcfLUDsgNF_EnMSRiFk74xvH5LRjM=/authenticate", fakeHub, logger.Logger, secPathTest, pubPathtest) fakeHub.RegisterNewChannel(name, authCha) _, found := fakeHub.channelByID[name] diff --git a/be1-go/old/channel/channel.go b/be1-go/internal/old/channel/channel.go similarity index 94% rename from be1-go/old/channel/channel.go rename to be1-go/internal/old/channel/channel.go index 73ca9423a8..e50b6c1bc1 100644 --- a/be1-go/old/channel/channel.go +++ b/be1-go/internal/old/channel/channel.go @@ -1,10 +1,10 @@ package channel import ( - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/validation" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/validation" "sync" "github.com/rs/zerolog" diff --git a/be1-go/old/channel/chirp/chirp.go b/be1-go/internal/old/channel/chirp/chirp.go similarity index 95% rename from be1-go/old/channel/chirp/chirp.go rename to be1-go/internal/old/channel/chirp/chirp.go index 324c198289..c67b64489b 100644 --- a/be1-go/old/channel/chirp/chirp.go +++ b/be1-go/internal/old/channel/chirp/chirp.go @@ -3,18 +3,18 @@ package chirp import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "time" diff --git a/be1-go/old/channel/chirp/chirp_test.go b/be1-go/internal/old/channel/chirp/chirp_test.go similarity index 97% rename from be1-go/old/channel/chirp/chirp_test.go rename to be1-go/internal/old/channel/chirp/chirp_test.go index 5a5b1efe69..20a7141366 100644 --- a/be1-go/old/channel/chirp/chirp_test.go +++ b/be1-go/internal/old/channel/chirp/chirp_test.go @@ -7,16 +7,16 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/generalChirping" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/generalChirping" + "popstellar/internal/validation" "sync" "testing" "time" @@ -34,8 +34,8 @@ const ( sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" generalName = "/root/" + laoID + "/social/posts" chirpChannelName = "/root/" + laoID + "/social/" + sender - relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" - relativeQueryExamplePath string = "../../../../protocol/examples/query" + relativeMsgDataExamplePath string = "../../../../../protocol/examples/messageData" + relativeQueryExamplePath string = "../../../../../protocol/examples/query" ) // Tests that the channel works correctly when it receives a subscribe from a diff --git a/be1-go/old/channel/coin/coin.go b/be1-go/internal/old/channel/coin/coin.go similarity index 92% rename from be1-go/old/channel/coin/coin.go rename to be1-go/internal/old/channel/coin/coin.go index d5178232fd..765ab35683 100644 --- a/be1-go/old/channel/coin/coin.go +++ b/be1-go/internal/old/channel/coin/coin.go @@ -5,17 +5,17 @@ import ( "encoding/json" "github.com/rs/zerolog" "golang.org/x/xerrors" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" ) diff --git a/be1-go/old/channel/coin/coin_test.go b/be1-go/internal/old/channel/coin/coin_test.go similarity index 98% rename from be1-go/old/channel/coin/coin_test.go rename to be1-go/internal/old/channel/coin/coin_test.go index 8678c8d44e..867fb5e9c8 100644 --- a/be1-go/old/channel/coin/coin_test.go +++ b/be1-go/internal/old/channel/coin/coin_test.go @@ -7,13 +7,13 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" @@ -26,7 +26,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../../protocol" +const protocolRelativePath string = "../../../validation/protocol" // Tests that the channel works correctly when it receives a subscribe func Test_General_Channel_Subscribe(t *testing.T) { diff --git a/be1-go/old/channel/consensus/consensus.go b/be1-go/internal/old/channel/consensus/consensus.go similarity index 98% rename from be1-go/old/channel/consensus/consensus.go rename to be1-go/internal/old/channel/consensus/consensus.go index cc9d2d42c1..7986289d17 100644 --- a/be1-go/old/channel/consensus/consensus.go +++ b/be1-go/internal/old/channel/consensus/consensus.go @@ -3,18 +3,18 @@ package consensus import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "sync" "time" diff --git a/be1-go/old/channel/consensus/consensus_test.go b/be1-go/internal/old/channel/consensus/consensus_test.go similarity index 99% rename from be1-go/old/channel/consensus/consensus_test.go rename to be1-go/internal/old/channel/consensus/consensus_test.go index 0b4286edca..84ec425fac 100644 --- a/be1-go/old/channel/consensus/consensus_test.go +++ b/be1-go/internal/old/channel/consensus/consensus_test.go @@ -7,15 +7,15 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" @@ -29,7 +29,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../../protocol" +const protocolRelativePath string = "../../../../../protocol" // Tests that the channel works correctly when it receives a subscribe from a // client diff --git a/be1-go/old/channel/consensus/message_creation.go b/be1-go/internal/old/channel/consensus/message_creation.go similarity index 99% rename from be1-go/old/channel/consensus/message_creation.go rename to be1-go/internal/old/channel/consensus/message_creation.go index 64372b414f..975009a2e9 100644 --- a/be1-go/old/channel/consensus/message_creation.go +++ b/be1-go/internal/old/channel/consensus/message_creation.go @@ -2,7 +2,7 @@ package consensus import ( "encoding/json" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "golang.org/x/xerrors" ) diff --git a/be1-go/old/channel/election/election.go b/be1-go/internal/old/channel/election/election.go similarity index 97% rename from be1-go/old/channel/election/election.go rename to be1-go/internal/old/channel/election/election.go index d6f9dc29af..9723c16bcd 100644 --- a/be1-go/old/channel/election/election.go +++ b/be1-go/internal/old/channel/election/election.go @@ -5,18 +5,18 @@ import ( "encoding/base64" "encoding/binary" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "strings" "sync" diff --git a/be1-go/old/channel/election/election_test.go b/be1-go/internal/old/channel/election/election_test.go similarity index 98% rename from be1-go/old/channel/election/election_test.go rename to be1-go/internal/old/channel/election/election_test.go index 664eae1c64..c7be3b652d 100644 --- a/be1-go/old/channel/election/election_test.go +++ b/be1-go/internal/old/channel/election/election_test.go @@ -8,13 +8,13 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" @@ -29,8 +29,8 @@ import ( ) const ( - relativeQueryExamplePath string = "../../../../protocol/examples/query" - relativeMsgDataExamplePath string = "../../../../protocol/examples/messageData" + relativeQueryExamplePath string = "../../../../../protocol/examples/query" + relativeMsgDataExamplePath string = "../../../../../protocol/examples/messageData" ) // Tests that the channel creation fails if two questions are the same diff --git a/be1-go/old/channel/election/verification.go b/be1-go/internal/old/channel/election/verification.go similarity index 99% rename from be1-go/old/channel/election/verification.go rename to be1-go/internal/old/channel/election/verification.go index 6d48ce835e..b50207ad39 100644 --- a/be1-go/old/channel/election/verification.go +++ b/be1-go/internal/old/channel/election/verification.go @@ -3,8 +3,8 @@ package election import ( "encoding/base64" "fmt" - "popstellar/message/answer" - "popstellar/message/messagedata" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" "sort" "strings" diff --git a/be1-go/old/channel/election/verification_test.go b/be1-go/internal/old/channel/election/verification_test.go similarity index 99% rename from be1-go/old/channel/election/verification_test.go rename to be1-go/internal/old/channel/election/verification_test.go index 79b98a6baa..579bf9bc07 100644 --- a/be1-go/old/channel/election/verification_test.go +++ b/be1-go/internal/old/channel/election/verification_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/old/channel/generalChirping/generalChirping.go b/be1-go/internal/old/channel/generalChirping/generalChirping.go similarity index 93% rename from be1-go/old/channel/generalChirping/generalChirping.go rename to be1-go/internal/old/channel/generalChirping/generalChirping.go index 5f370d0be0..40ec16b18e 100644 --- a/be1-go/old/channel/generalChirping/generalChirping.go +++ b/be1-go/internal/old/channel/generalChirping/generalChirping.go @@ -3,18 +3,18 @@ package generalChirping import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "github.com/rs/zerolog" diff --git a/be1-go/old/channel/generalChirping/generalChirping_test.go b/be1-go/internal/old/channel/generalChirping/generalChirping_test.go similarity index 96% rename from be1-go/old/channel/generalChirping/generalChirping_test.go rename to be1-go/internal/old/channel/generalChirping/generalChirping_test.go index e899924607..5a62a4456c 100644 --- a/be1-go/old/channel/generalChirping/generalChirping_test.go +++ b/be1-go/internal/old/channel/generalChirping/generalChirping_test.go @@ -6,12 +6,12 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" @@ -24,7 +24,7 @@ import ( "golang.org/x/xerrors" ) -const protocolRelativePath string = "../../../../protocol" +const protocolRelativePath string = "../../../validation/protocol" // Tests that the channel works correctly when it receives a subscribe func Test_General_Channel_Subscribe(t *testing.T) { diff --git a/be1-go/old/channel/lao/lao.go b/be1-go/internal/old/channel/lao/lao.go similarity index 96% rename from be1-go/old/channel/lao/lao.go rename to be1-go/internal/old/channel/lao/lao.go index 8c87c9fb33..fa8e878d0b 100644 --- a/be1-go/old/channel/lao/lao.go +++ b/be1-go/internal/old/channel/lao/lao.go @@ -4,26 +4,26 @@ import ( "encoding/base64" "encoding/json" "fmt" - popstellar "popstellar" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/authentication" - "popstellar/old/channel/chirp" - "popstellar/old/channel/coin" - "popstellar/old/channel/consensus" - "popstellar/old/channel/election" - "popstellar/old/channel/generalChirping" - "popstellar/old/channel/reaction" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + popstellar "popstellar/internal/logger" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/authentication" + "popstellar/internal/old/channel/chirp" + "popstellar/internal/old/channel/coin" + "popstellar/internal/old/channel/consensus" + "popstellar/internal/old/channel/election" + "popstellar/internal/old/channel/generalChirping" + "popstellar/internal/old/channel/reaction" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "strings" "sync" diff --git a/be1-go/old/channel/lao/lao_test.go b/be1-go/internal/old/channel/lao/lao_test.go similarity index 98% rename from be1-go/old/channel/lao/lao_test.go rename to be1-go/internal/old/channel/lao/lao_test.go index b9ed1e0063..afe524ce5d 100644 --- a/be1-go/old/channel/lao/lao_test.go +++ b/be1-go/internal/old/channel/lao/lao_test.go @@ -8,15 +8,15 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "strconv" "sync" "testing" @@ -30,7 +30,7 @@ import ( "github.com/stretchr/testify/require" ) -const protocolRelativePath string = "../../../../protocol" +const protocolRelativePath string = "../../../validation/protocol" func TestLAOChannel_Subscribe(t *testing.T) { keypair := generateKeyPair(t) diff --git a/be1-go/old/channel/lao/verification.go b/be1-go/internal/old/channel/lao/verification.go similarity index 99% rename from be1-go/old/channel/lao/verification.go rename to be1-go/internal/old/channel/lao/verification.go index 85b56537e6..3a73094149 100644 --- a/be1-go/old/channel/lao/verification.go +++ b/be1-go/internal/old/channel/lao/verification.go @@ -2,7 +2,7 @@ package lao import ( "encoding/base64" - "popstellar/message/messagedata" + "popstellar/internal/message/messagedata" "strconv" "strings" diff --git a/be1-go/old/channel/lao/verification_test.go b/be1-go/internal/old/channel/lao/verification_test.go similarity index 97% rename from be1-go/old/channel/lao/verification_test.go rename to be1-go/internal/old/channel/lao/verification_test.go index 851fef7204..32edadbb74 100644 --- a/be1-go/old/channel/lao/verification_test.go +++ b/be1-go/internal/old/channel/lao/verification_test.go @@ -4,9 +4,9 @@ import ( "encoding/json" "os" "path/filepath" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" - "popstellar/old/channel" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/old/channel" "testing" "github.com/stretchr/testify/require" @@ -15,7 +15,7 @@ import ( var relativeExamplePath string func init() { - relativeExamplePath = filepath.Join("..", "..", "..", "..", "protocol", + relativeExamplePath = filepath.Join("..", "..", "..", "validation", "protocol", "examples", "messageData") } diff --git a/be1-go/old/channel/reaction/reaction.go b/be1-go/internal/old/channel/reaction/reaction.go similarity index 94% rename from be1-go/old/channel/reaction/reaction.go rename to be1-go/internal/old/channel/reaction/reaction.go index 791fb5e4e6..53ca9545dc 100644 --- a/be1-go/old/channel/reaction/reaction.go +++ b/be1-go/internal/old/channel/reaction/reaction.go @@ -3,18 +3,18 @@ package reaction import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/channel/registry" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/channel/registry" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strconv" "sync" "time" diff --git a/be1-go/old/channel/reaction/reaction_test.go b/be1-go/internal/old/channel/reaction/reaction_test.go similarity index 97% rename from be1-go/old/channel/reaction/reaction_test.go rename to be1-go/internal/old/channel/reaction/reaction_test.go index f13545a80d..1ddf9d3b38 100644 --- a/be1-go/old/channel/reaction/reaction_test.go +++ b/be1-go/internal/old/channel/reaction/reaction_test.go @@ -7,15 +7,15 @@ import ( "io" "os" "path/filepath" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/validation" "sync" "testing" "time" @@ -32,7 +32,7 @@ const ( laoID = "fzJSZjKf-2cbXH7kds9H8NORuuFIRLkevJlN7qQemjo=" sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" reactionChannelName = "/root/" + laoID + "/social/reactions" - protocolRelativePath string = "../../../../protocol" + protocolRelativePath string = "../../../validation/protocol" ) // Tests that the channel works correctly when it receives a subscribe from a diff --git a/be1-go/old/channel/registry/registry.go b/be1-go/internal/old/channel/registry/registry.go similarity index 94% rename from be1-go/old/channel/registry/registry.go rename to be1-go/internal/old/channel/registry/registry.go index d002bca1a0..7be4ffea8a 100644 --- a/be1-go/old/channel/registry/registry.go +++ b/be1-go/internal/old/channel/registry/registry.go @@ -2,9 +2,9 @@ package registry import ( "encoding/base64" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" - "popstellar/network/socket" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" "golang.org/x/xerrors" ) diff --git a/be1-go/old/hub/hub.go b/be1-go/internal/old/hub/hub.go similarity index 96% rename from be1-go/old/hub/hub.go rename to be1-go/internal/old/hub/hub.go index 9045062c4a..c70f6eaad1 100644 --- a/be1-go/old/hub/hub.go +++ b/be1-go/internal/old/hub/hub.go @@ -4,7 +4,7 @@ package hub import ( - "popstellar/network/socket" + "popstellar/internal/network/socket" ) // Hub defines the methods a PoP server must implement to receive messages diff --git a/be1-go/old/hub/standard_hub/hub_state/channels.go b/be1-go/internal/old/hub/standard_hub/hub_state/channels.go similarity index 93% rename from be1-go/old/hub/standard_hub/hub_state/channels.go rename to be1-go/internal/old/hub/standard_hub/hub_state/channels.go index 5aa0b7470f..230b9adfed 100644 --- a/be1-go/old/hub/standard_hub/hub_state/channels.go +++ b/be1-go/internal/old/hub/standard_hub/hub_state/channels.go @@ -1,7 +1,7 @@ package hub_state import ( - "popstellar/old/channel" + "popstellar/internal/old/channel" ) // Channels stores channel ids with their corresponding channels diff --git a/be1-go/old/hub/standard_hub/hub_state/messageIds.go b/be1-go/internal/old/hub/standard_hub/hub_state/messageIds.go similarity index 100% rename from be1-go/old/hub/standard_hub/hub_state/messageIds.go rename to be1-go/internal/old/hub/standard_hub/hub_state/messageIds.go diff --git a/be1-go/old/hub/standard_hub/hub_state/peers.go b/be1-go/internal/old/hub/standard_hub/hub_state/peers.go similarity index 95% rename from be1-go/old/hub/standard_hub/hub_state/peers.go rename to be1-go/internal/old/hub/standard_hub/hub_state/peers.go index bec2e1c201..104926a2a7 100644 --- a/be1-go/old/hub/standard_hub/hub_state/peers.go +++ b/be1-go/internal/old/hub/standard_hub/hub_state/peers.go @@ -1,8 +1,8 @@ package hub_state import ( - "popstellar/message/answer" - "popstellar/message/query/method" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" "sync" "golang.org/x/exp/maps" diff --git a/be1-go/old/hub/standard_hub/hub_state/queries.go b/be1-go/internal/old/hub/standard_hub/hub_state/queries.go similarity index 97% rename from be1-go/old/hub/standard_hub/hub_state/queries.go rename to be1-go/internal/old/hub/standard_hub/hub_state/queries.go index 74e8fdff30..b09dea0311 100644 --- a/be1-go/old/hub/standard_hub/hub_state/queries.go +++ b/be1-go/internal/old/hub/standard_hub/hub_state/queries.go @@ -1,7 +1,7 @@ package hub_state import ( - "popstellar/message/query/method" + "popstellar/internal/message/query/method" "sync" "github.com/rs/zerolog" diff --git a/be1-go/old/hub/standard_hub/hub_state/threadSafeMap.go b/be1-go/internal/old/hub/standard_hub/hub_state/threadSafeMap.go similarity index 100% rename from be1-go/old/hub/standard_hub/hub_state/threadSafeMap.go rename to be1-go/internal/old/hub/standard_hub/hub_state/threadSafeMap.go diff --git a/be1-go/old/hub/standard_hub/hub_state/threadSafeSlice.go b/be1-go/internal/old/hub/standard_hub/hub_state/threadSafeSlice.go similarity index 100% rename from be1-go/old/hub/standard_hub/hub_state/threadSafeSlice.go rename to be1-go/internal/old/hub/standard_hub/hub_state/threadSafeSlice.go diff --git a/be1-go/old/hub/standard_hub/message_handling.go b/be1-go/internal/old/hub/standard_hub/message_handling.go similarity index 97% rename from be1-go/old/hub/standard_hub/message_handling.go rename to be1-go/internal/old/hub/standard_hub/message_handling.go index d2238d0d1b..cb0d188e09 100644 --- a/be1-go/old/hub/standard_hub/message_handling.go +++ b/be1-go/internal/old/hub/standard_hub/message_handling.go @@ -3,16 +3,16 @@ package standard_hub import ( "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/hub/standard_hub/hub_state" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/hub/standard_hub/hub_state" + "popstellar/internal/validation" "github.com/rs/zerolog/log" diff --git a/be1-go/old/hub/standard_hub/standard_hub.go b/be1-go/internal/old/hub/standard_hub/standard_hub.go similarity index 97% rename from be1-go/old/hub/standard_hub/standard_hub.go rename to be1-go/internal/old/hub/standard_hub/standard_hub.go index d66e2dbbaf..f01273ab72 100644 --- a/be1-go/old/hub/standard_hub/standard_hub.go +++ b/be1-go/internal/old/hub/standard_hub/standard_hub.go @@ -4,18 +4,18 @@ import ( "context" "encoding/base64" "encoding/json" - "popstellar/crypto" - jsonrpc "popstellar/message" - "popstellar/message/answer" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" - "popstellar/old/hub/standard_hub/hub_state" - "popstellar/old/inbox" - "popstellar/validation" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" + "popstellar/internal/old/hub/standard_hub/hub_state" + "popstellar/internal/old/inbox" + "popstellar/internal/validation" "strings" "sync" "time" diff --git a/be1-go/old/hub/standard_hub/standard_hub_test.go b/be1-go/internal/old/hub/standard_hub/standard_hub_test.go similarity index 99% rename from be1-go/old/hub/standard_hub/standard_hub_test.go rename to be1-go/internal/old/hub/standard_hub/standard_hub_test.go index 02ed7bc69a..fe83d4f209 100644 --- a/be1-go/old/hub/standard_hub/standard_hub_test.go +++ b/be1-go/internal/old/hub/standard_hub/standard_hub_test.go @@ -8,13 +8,13 @@ import ( "io" "os" "path/filepath" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" - "popstellar/network/socket" - "popstellar/old/channel" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" + "popstellar/internal/old/channel" "sync" "testing" "time" @@ -846,7 +846,7 @@ func Test_Handle_Answer(t *testing.T) { ID: 1, Result: make([]message.Message, 1), } - messageDataPath := filepath.Join("..", "..", "..", "..", "protocol", + messageDataPath := filepath.Join("..", "..", "..", "validation", "protocol", "examples", "messageData", "lao_create", "lao_create.json") messageDataBuf, err := os.ReadFile(messageDataPath) diff --git a/be1-go/old/inbox/hub_inbox.go b/be1-go/internal/old/inbox/hub_inbox.go similarity index 93% rename from be1-go/old/inbox/hub_inbox.go rename to be1-go/internal/old/inbox/hub_inbox.go index d977caa91b..f4f9b8708b 100644 --- a/be1-go/old/inbox/hub_inbox.go +++ b/be1-go/internal/old/inbox/hub_inbox.go @@ -1,8 +1,8 @@ package inbox import ( - "popstellar/message/query/method/message" - state "popstellar/old/hub/standard_hub/hub_state" + "popstellar/internal/message/query/method/message" + state "popstellar/internal/old/hub/standard_hub/hub_state" "sync" ) diff --git a/be1-go/old/inbox/inbox.go b/be1-go/internal/old/inbox/inbox.go similarity index 98% rename from be1-go/old/inbox/inbox.go rename to be1-go/internal/old/inbox/inbox.go index e51cd43e44..717cef51c1 100644 --- a/be1-go/old/inbox/inbox.go +++ b/be1-go/internal/old/inbox/inbox.go @@ -5,7 +5,7 @@ import ( "sync" "time" - "popstellar/message/query/method/message" + "popstellar/internal/message/query/method/message" ) // messageInfo wraps a message with a stored time for sorting. diff --git a/be1-go/old/inbox/inbox_test.go b/be1-go/internal/old/inbox/inbox_test.go similarity index 98% rename from be1-go/old/inbox/inbox_test.go rename to be1-go/internal/old/inbox/inbox_test.go index a3ac974fab..28e0322bbc 100644 --- a/be1-go/old/inbox/inbox_test.go +++ b/be1-go/internal/old/inbox/inbox_test.go @@ -4,7 +4,7 @@ import ( "crypto/sha256" "encoding/base64" "fmt" - "popstellar/message/query/method/message" + "popstellar/internal/message/query/method/message" "testing" "github.com/stretchr/testify/require" diff --git a/be1-go/popcha/docs/README.md b/be1-go/internal/popcha/docs/README.md similarity index 100% rename from be1-go/popcha/docs/README.md rename to be1-go/internal/popcha/docs/README.md diff --git a/be1-go/popcha/qrcode/popcha.html b/be1-go/internal/popcha/qrcode/popcha.html similarity index 100% rename from be1-go/popcha/qrcode/popcha.html rename to be1-go/internal/popcha/qrcode/popcha.html diff --git a/be1-go/popcha/server.go b/be1-go/internal/popcha/server.go similarity index 99% rename from be1-go/popcha/server.go rename to be1-go/internal/popcha/server.go index 9d6cb0f083..12594bcc7c 100644 --- a/be1-go/popcha/server.go +++ b/be1-go/internal/popcha/server.go @@ -17,7 +17,7 @@ import ( "html/template" "io/fs" "net/http" - "popstellar/old/hub" + "popstellar/internal/old/hub" "strconv" "strings" "sync" diff --git a/be1-go/popcha/server_test.go b/be1-go/internal/popcha/server_test.go similarity index 98% rename from be1-go/popcha/server_test.go rename to be1-go/internal/popcha/server_test.go index 0c0d03966f..23505b5950 100644 --- a/be1-go/popcha/server_test.go +++ b/be1-go/internal/popcha/server_test.go @@ -9,10 +9,10 @@ import ( "net/http" "net/url" "os" - "popstellar" - "popstellar/crypto" - "popstellar/old/hub" - "popstellar/old/hub/standard_hub" + "popstellar/internal/crypto" + "popstellar/internal/logger" + "popstellar/internal/old/hub" + "popstellar/internal/old/hub/standard_hub" "reflect" "strings" "testing" @@ -53,7 +53,7 @@ func genString(r *rand.Rand, s int) string { // TestAuthServerStartAndShutdown tests if the authorization server correctly starts and stops. func TestAuthServerStartAndShutdown(t *testing.T) { - l := popstellar.Logger + l := logger.Logger h, err := standard_hub.NewHub(crypto.Suite.Point(), "", "", l, nil) require.NoError(t, err, "could not create hub") @@ -73,7 +73,7 @@ func TestAuthServerStartAndShutdown(t *testing.T) { // TestAuthorizationServerHandleValidateRequest tests if , when receiving a valid authorization request, // the server serves a webpage with the associated QRCode. func TestAuthorizationServerHandleValidateRequest(t *testing.T) { - l := popstellar.Logger + l := logger.Logger s, err := NewAuthServer(fakeHub{}, "localhost", 3003, l) require.NoError(t, err) s.Start() @@ -215,7 +215,7 @@ func helperMissingArgs(t *testing.T, body []byte, n int) { func TestAuthorizationServerWebsocket(t *testing.T) { // starting the authorization server - l := popstellar.Logger + l := logger.Logger s, err := NewAuthServer(fakeHub{}, "localhost", 3004, l) require.NoError(t, err) s.Start() diff --git a/be1-go/internal/popserver/database/database.go b/be1-go/internal/popserver/database/database.go deleted file mode 100644 index 3fcf848db4..0000000000 --- a/be1-go/internal/popserver/database/database.go +++ /dev/null @@ -1,71 +0,0 @@ -package database - -import ( - "popstellar/internal/popserver/database/repository" - "popstellar/message/answer" - "sync" -) - -var once sync.Once -var instance repository.Repository - -func InitDatabase(db repository.Repository) { - once.Do(func() { - instance = db - }) -} - -// ONLY FOR TEST PURPOSE -// SetDatabase is only here to be used to reset the database before each test -func SetDatabase(mockRepo *repository.MockRepository) { - instance = mockRepo -} - -func getInstance() (repository.Repository, *answer.Error) { - if instance == nil { - errAnswer := answer.NewInternalServerError("database was not instantiated") - return nil, errAnswer - } - - return instance, nil -} - -func GetRumorSenderRepositoryInstance() (repository.RumorSenderRepository, *answer.Error) { - return getInstance() -} - -func GetQueryRepositoryInstance() (repository.QueryRepository, *answer.Error) { - return getInstance() -} - -func GetChannelRepositoryInstance() (repository.ChannelRepository, *answer.Error) { - return getInstance() -} - -func GetRootRepositoryInstance() (repository.RootRepository, *answer.Error) { - return getInstance() -} - -func GetLAORepositoryInstance() (repository.LAORepository, *answer.Error) { - return getInstance() -} - -func GetChirpRepositoryInstance() (repository.ChirpRepository, *answer.Error) { - return getInstance() -} - -func GetCoinRepositoryInstance() (repository.CoinRepository, *answer.Error) { - return getInstance() -} - -func GetElectionRepositoryInstance() (repository.ElectionRepository, *answer.Error) { - return getInstance() -} - -func GetReactionRepositoryInstance() (repository.ReactionRepository, *answer.Error) { - return getInstance() -} - -func GetFederationRepositoryInstance() (repository.FederationRepository, *answer.Error) { - return getInstance() -} diff --git a/be1-go/internal/popserver/database/repository/mock_repository.go b/be1-go/internal/repository/mock_repository.go similarity index 99% rename from be1-go/internal/popserver/database/repository/mock_repository.go rename to be1-go/internal/repository/mock_repository.go index d7dcadd727..f6233c3280 100644 --- a/be1-go/internal/popserver/database/repository/mock_repository.go +++ b/be1-go/internal/repository/mock_repository.go @@ -3,16 +3,15 @@ package repository import ( - messagedata "popstellar/message/messagedata" - message "popstellar/message/query/method/message" + messagedata "popstellar/internal/message/messagedata" + message "popstellar/internal/message/query/method/message" + "popstellar/internal/types" kyber "go.dedis.ch/kyber/v3" - method "popstellar/message/query/method" + method "popstellar/internal/message/query/method" mock "github.com/stretchr/testify/mock" - - types "popstellar/internal/popserver/types" ) // MockRepository is an autogenerated mock type for the Repository type diff --git a/be1-go/internal/popserver/database/repository/repository.go b/be1-go/internal/repository/repository.go similarity index 98% rename from be1-go/internal/popserver/database/repository/repository.go rename to be1-go/internal/repository/repository.go index b3dbbb6350..caa1541e48 100644 --- a/be1-go/internal/popserver/database/repository/repository.go +++ b/be1-go/internal/repository/repository.go @@ -2,10 +2,10 @@ package repository import ( "go.dedis.ch/kyber/v3" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/types" ) type Repository interface { diff --git a/be1-go/internal/popserver/config/config.go b/be1-go/internal/singleton/config/config.go similarity index 98% rename from be1-go/internal/popserver/config/config.go rename to be1-go/internal/singleton/config/config.go index ed37e64ab6..e9b836308f 100644 --- a/be1-go/internal/popserver/config/config.go +++ b/be1-go/internal/singleton/config/config.go @@ -3,7 +3,7 @@ package config import ( "encoding/base64" "go.dedis.ch/kyber/v3" - "popstellar/message/answer" + "popstellar/internal/message/answer" "sync" ) diff --git a/be1-go/internal/singleton/database/database.go b/be1-go/internal/singleton/database/database.go new file mode 100644 index 0000000000..6f7cbde70f --- /dev/null +++ b/be1-go/internal/singleton/database/database.go @@ -0,0 +1,71 @@ +package database + +import ( + "popstellar/internal/message/answer" + repository2 "popstellar/internal/repository" + "sync" +) + +var once sync.Once +var instance repository2.Repository + +func InitDatabase(db repository2.Repository) { + once.Do(func() { + instance = db + }) +} + +// ONLY FOR TEST PURPOSE +// SetDatabase is only here to be used to reset the database before each test +func SetDatabase(mockRepo *repository2.MockRepository) { + instance = mockRepo +} + +func getInstance() (repository2.Repository, *answer.Error) { + if instance == nil { + errAnswer := answer.NewInternalServerError("database was not instantiated") + return nil, errAnswer + } + + return instance, nil +} + +func GetRumorSenderRepositoryInstance() (repository2.RumorSenderRepository, *answer.Error) { + return getInstance() +} + +func GetQueryRepositoryInstance() (repository2.QueryRepository, *answer.Error) { + return getInstance() +} + +func GetChannelRepositoryInstance() (repository2.ChannelRepository, *answer.Error) { + return getInstance() +} + +func GetRootRepositoryInstance() (repository2.RootRepository, *answer.Error) { + return getInstance() +} + +func GetLAORepositoryInstance() (repository2.LAORepository, *answer.Error) { + return getInstance() +} + +func GetChirpRepositoryInstance() (repository2.ChirpRepository, *answer.Error) { + return getInstance() +} + +func GetCoinRepositoryInstance() (repository2.CoinRepository, *answer.Error) { + return getInstance() +} + +func GetElectionRepositoryInstance() (repository2.ElectionRepository, *answer.Error) { + return getInstance() +} + +func GetReactionRepositoryInstance() (repository2.ReactionRepository, *answer.Error) { + return getInstance() +} + +func GetFederationRepositoryInstance() (repository2.FederationRepository, *answer.Error) { + return getInstance() +} diff --git a/be1-go/internal/popserver/state/hub_parameter.go b/be1-go/internal/singleton/state/hub_parameter.go similarity index 93% rename from be1-go/internal/popserver/state/hub_parameter.go rename to be1-go/internal/singleton/state/hub_parameter.go index 179196643c..9b6e2957fb 100644 --- a/be1-go/internal/popserver/state/hub_parameter.go +++ b/be1-go/internal/singleton/state/hub_parameter.go @@ -1,8 +1,8 @@ package state import ( - "popstellar/message/answer" - "popstellar/network/socket" + "popstellar/internal/message/answer" + "popstellar/internal/network/socket" "sync" ) diff --git a/be1-go/internal/popserver/state/peerer.go b/be1-go/internal/singleton/state/peerer.go similarity index 94% rename from be1-go/internal/popserver/state/peerer.go rename to be1-go/internal/singleton/state/peerer.go index 8d3e379e86..b3f1e11ad9 100644 --- a/be1-go/internal/popserver/state/peerer.go +++ b/be1-go/internal/singleton/state/peerer.go @@ -1,8 +1,8 @@ package state import ( - "popstellar/message/answer" - "popstellar/message/query/method" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" ) type Peerer interface { diff --git a/be1-go/internal/popserver/state/querier.go b/be1-go/internal/singleton/state/querier.go similarity index 95% rename from be1-go/internal/popserver/state/querier.go rename to be1-go/internal/singleton/state/querier.go index ec16cd357a..c437db96e3 100644 --- a/be1-go/internal/popserver/state/querier.go +++ b/be1-go/internal/singleton/state/querier.go @@ -1,8 +1,8 @@ package state import ( - "popstellar/message/answer" - "popstellar/message/query/method" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" ) type Querier interface { diff --git a/be1-go/internal/popserver/state/socketer.go b/be1-go/internal/singleton/state/socketer.go similarity index 94% rename from be1-go/internal/popserver/state/socketer.go rename to be1-go/internal/singleton/state/socketer.go index dbdb68321f..e59b98855e 100644 --- a/be1-go/internal/popserver/state/socketer.go +++ b/be1-go/internal/singleton/state/socketer.go @@ -1,8 +1,8 @@ package state import ( - "popstellar/message/answer" - "popstellar/network/socket" + "popstellar/internal/message/answer" + "popstellar/internal/network/socket" ) type Socketer interface { diff --git a/be1-go/internal/popserver/state/state.go b/be1-go/internal/singleton/state/state.go similarity index 81% rename from be1-go/internal/popserver/state/state.go rename to be1-go/internal/singleton/state/state.go index b441a78d0c..d61a881712 100644 --- a/be1-go/internal/popserver/state/state.go +++ b/be1-go/internal/singleton/state/state.go @@ -2,8 +2,8 @@ package state import ( "github.com/rs/zerolog" - "popstellar/internal/popserver/types" - "popstellar/message/answer" + "popstellar/internal/message/answer" + types2 "popstellar/internal/types" "sync" ) @@ -22,11 +22,11 @@ type state struct { func InitState(log *zerolog.Logger) { once.Do(func() { instance = &state{ - subs: types.NewSubscribers(), - peers: types.NewPeers(), - queries: types.NewQueries(log), - hubParams: types.NewHubParams(), - sockets: types.NewSockets(), + subs: types2.NewSubscribers(), + peers: types2.NewPeers(), + queries: types2.NewQueries(log), + hubParams: types2.NewHubParams(), + sockets: types2.NewSockets(), resetRumorSender: make(chan struct{}), } }) diff --git a/be1-go/internal/popserver/state/subscriber.go b/be1-go/internal/singleton/state/subscriber.go similarity index 95% rename from be1-go/internal/popserver/state/subscriber.go rename to be1-go/internal/singleton/state/subscriber.go index c94514d488..2550089411 100644 --- a/be1-go/internal/popserver/state/subscriber.go +++ b/be1-go/internal/singleton/state/subscriber.go @@ -1,8 +1,8 @@ package state import ( - "popstellar/message/answer" - "popstellar/network/socket" + "popstellar/internal/message/answer" + "popstellar/internal/network/socket" ) type Subscriber interface { diff --git a/be1-go/internal/popserver/utils/utils.go b/be1-go/internal/singleton/utils/utils.go similarity index 93% rename from be1-go/internal/popserver/utils/utils.go rename to be1-go/internal/singleton/utils/utils.go index 5d7a74ac5b..c1d22f965e 100644 --- a/be1-go/internal/popserver/utils/utils.go +++ b/be1-go/internal/singleton/utils/utils.go @@ -3,8 +3,8 @@ package utils import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "popstellar/message/answer" - "popstellar/validation" + "popstellar/internal/message/answer" + "popstellar/internal/validation" "sync" ) diff --git a/be1-go/internal/popserver/database/sqlite/sqlite.go b/be1-go/internal/sqlite/sqlite.go similarity index 99% rename from be1-go/internal/popserver/database/sqlite/sqlite.go rename to be1-go/internal/sqlite/sqlite.go index d18d553745..fe9709205a 100644 --- a/be1-go/internal/popserver/database/sqlite/sqlite.go +++ b/be1-go/internal/sqlite/sqlite.go @@ -8,13 +8,13 @@ import ( "go.dedis.ch/kyber/v3" "golang.org/x/xerrors" _ "modernc.org/sqlite" - "popstellar/crypto" - "popstellar/internal/popserver/types" - jsonrpc "popstellar/message" - "popstellar/message/messagedata" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" + "popstellar/internal/types" "strings" "time" ) diff --git a/be1-go/internal/popserver/database/sqlite/sqlite_const.go b/be1-go/internal/sqlite/sqlite_const.go similarity index 100% rename from be1-go/internal/popserver/database/sqlite/sqlite_const.go rename to be1-go/internal/sqlite/sqlite_const.go diff --git a/be1-go/internal/popserver/database/sqlite/sqlite_init.go b/be1-go/internal/sqlite/sqlite_init.go similarity index 98% rename from be1-go/internal/popserver/database/sqlite/sqlite_init.go rename to be1-go/internal/sqlite/sqlite_init.go index e20e03cf67..4d8cffc6e7 100644 --- a/be1-go/internal/popserver/database/sqlite/sqlite_init.go +++ b/be1-go/internal/sqlite/sqlite_init.go @@ -4,7 +4,7 @@ import ( "database/sql" "encoding/base64" "go.dedis.ch/kyber/v3" - database2 "popstellar/internal/popserver/database/repository" + database2 "popstellar/internal/repository" "sync" ) diff --git a/be1-go/internal/popserver/database/sqlite/sqlite_test.go b/be1-go/internal/sqlite/sqlite_test.go similarity index 89% rename from be1-go/internal/popserver/database/sqlite/sqlite_test.go rename to be1-go/internal/sqlite/sqlite_test.go index e23661c4ed..fddb850ed2 100644 --- a/be1-go/internal/popserver/database/sqlite/sqlite_test.go +++ b/be1-go/internal/sqlite/sqlite_test.go @@ -8,11 +8,11 @@ import ( "github.com/stretchr/testify/require" "os" "path/filepath" - "popstellar/crypto" - "popstellar/internal/popserver/generatortest" - "popstellar/internal/popserver/types" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + generatortest2 "popstellar/internal/test/generatortest" + "popstellar/internal/types" "sort" "testing" "time" @@ -318,7 +318,7 @@ func Test_SQLite_StoreLaoWithLaoGreet(t *testing.T) { laoID := "laoID" - laoCreateMsg := generatortest.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, + laoCreateMsg := generatortest2.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, organizerPubBuf64, nil) laoGreet := messagedata.LaoGreet{ @@ -389,9 +389,9 @@ func Test_SQLite_GetRollCallState(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generatortest2.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallOpen := generatortest2.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) states := []string{"create", "open", "close"} messages := []message.Message{rollCallCreate, rollCallOpen, rollCallClose} @@ -410,8 +410,8 @@ func Test_SQLite_CheckPrevOpenOrReopenID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallReopen := generatortest.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) + rollCallOpen := generatortest2.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallReopen := generatortest2.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) err = lite.StoreMessageAndData("channel1", rollCallOpen) require.NoError(t, err) @@ -434,8 +434,8 @@ func Test_SQLite_CheckPrevCreateOrCloseID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generatortest2.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreMessageAndData("channel1", rollCallCreate) require.NoError(t, err) @@ -461,7 +461,7 @@ func Test_SQLite_StoreRollCallClose(t *testing.T) { channels := []string{"channel1", "channel2", "channel3"} laoID := "laoID" - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreRollCallClose(channels, laoID, rollCallClose) require.NoError(t, err) @@ -492,7 +492,7 @@ func Test_SQLite_StoreElectionWithElectionKey(t *testing.T) { electionPubBuf, err := point.MarshalBinary() require.NoError(t, err) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) electionKey := messagedata.ElectionKey{ @@ -542,7 +542,7 @@ func Test_SQLite_StoreElection(t *testing.T) { secret := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) point := crypto.Suite.Point().Mul(secret, nil) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) err = lite.StoreElection(laoID, electionID, point, secret, electionSetupMsg) @@ -576,7 +576,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionOpenMsg := generatortest.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) + electionOpenMsg := generatortest2.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) err = lite.StoreMessageAndData(electionID, electionOpenMsg) require.NoError(t, err) @@ -592,7 +592,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionCloseMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionCloseMsg := generatortest2.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) err = lite.StoreMessageAndData(electionID, electionCloseMsg) require.NoError(t, err) @@ -619,7 +619,7 @@ func Test_SQLite_GetElectionCreationTimeAndType(t *testing.T) { electionPath := "electionPath" creationTime := int64(123456789) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, creationTime, 2, 3, nil, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -645,7 +645,7 @@ func Test_SQLite_GetElectionAttendees(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} expected := map[string]struct{}{"attendee1": {}, "attendee2": {}, "attendee3": {}} - rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) + rollCallCloseMsg := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) require.NoError(t, err) @@ -677,7 +677,7 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { }, } - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, 1, 2, 3, questions, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -694,9 +694,9 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.NoError(t, err) // Add votes to the election - vote1 := generatortest.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} - votes := []generatortest.VoteString{vote1} - castVoteMsg := generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote1 := generatortest2.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} + votes := []generatortest2.VoteString{vote1} + castVoteMsg := generatortest2.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 1, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) @@ -713,9 +713,9 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.Equal(t, expected, result) // Add more votes to the election - vote2 := generatortest.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} - votes = []generatortest.VoteString{vote2} - castVoteMsg = generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote2 := generatortest2.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} + votes = []generatortest2.VoteString{vote2} + castVoteMsg = generatortest2.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 2, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) @@ -742,8 +742,8 @@ func Test_SQLite_StoreElectionEndWithResult(t *testing.T) { laoID := "laoID" electionID := "electionID" - electionEndMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) - electionResultMsg := generatortest.NewElectionResultMsg(t, "sender2", nil, nil) + electionEndMsg := generatortest2.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionResultMsg := generatortest2.NewElectionResultMsg(t, "sender2", nil, nil) err = lite.StoreElectionEndWithResult(electionPath, electionEndMsg, electionResultMsg) require.NoError(t, err) @@ -763,7 +763,7 @@ func Test_SQLite_StoreChirpMessages(t *testing.T) { chirpPath := "chirpID" generalChirpPath := "generalChirpID" - chirpMsg := generatortest.NewChirpAddMsg(t, "sender1", nil, 1) + chirpMsg := generatortest2.NewChirpAddMsg(t, "sender1", nil, 1) generalChirpMsg := message.Message{ Data: base64.URLEncoding.EncodeToString([]byte("data")), Sender: "sender1", @@ -795,7 +795,7 @@ func Test_SQLite_IsAttendee(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} laoID := "laoID" - rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", + rollCallCloseMsg := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) @@ -817,7 +817,7 @@ func Test_SQLite_GetReactionSender(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - reactionAddMsg := generatortest.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) + reactionAddMsg := generatortest2.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) sender, err := lite.GetReactionSender(reactionAddMsg.MessageID) require.NoError(t, err) @@ -849,7 +849,7 @@ func Test_SQLite_IsChallengeValid(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, sender, value, + challengeMsg := generatortest2.NewFederationChallenge(t, sender, value, validUntil, nil) err = lite.StoreMessageAndData(fedPath, challengeMsg) @@ -894,10 +894,10 @@ func Test_SQLite_GetFederationExpect(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generatortest2.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest.NewFederationExpect(t, organizer, laoId, + expectMsg := generatortest2.NewFederationExpect(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationExpect(organizer, organizer2, challenge, fedPath) @@ -940,10 +940,10 @@ func Test_SQLite_GetFederationInit(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generatortest2.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest.NewFederationInit(t, organizer, laoId, + expectMsg := generatortest2.NewFederationInit(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationInit(organizer, organizer2, challenge, fedPath) diff --git a/be1-go/internal/popserver/generatortest/chirp.go b/be1-go/internal/test/generatortest/chirp.go similarity index 91% rename from be1-go/internal/popserver/generatortest/chirp.go rename to be1-go/internal/test/generatortest/chirp.go index e918aa9aec..c60efb1a67 100644 --- a/be1-go/internal/popserver/generatortest/chirp.go +++ b/be1-go/internal/test/generatortest/chirp.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/election.go b/be1-go/internal/test/generatortest/election.go similarity index 97% rename from be1-go/internal/popserver/generatortest/election.go rename to be1-go/internal/test/generatortest/election.go index 6c20e9ef28..509e0e02b0 100644 --- a/be1-go/internal/popserver/generatortest/election.go +++ b/be1-go/internal/test/generatortest/election.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/federation.go b/be1-go/internal/test/generatortest/federation.go similarity index 97% rename from be1-go/internal/popserver/generatortest/federation.go rename to be1-go/internal/test/generatortest/federation.go index f200340211..0a440c51e6 100644 --- a/be1-go/internal/popserver/generatortest/federation.go +++ b/be1-go/internal/test/generatortest/federation.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/generatortest.go b/be1-go/internal/test/generatortest/generatortest.go similarity index 92% rename from be1-go/internal/popserver/generatortest/generatortest.go rename to be1-go/internal/test/generatortest/generatortest.go index 39d8838af2..b176e69933 100644 --- a/be1-go/internal/popserver/generatortest/generatortest.go +++ b/be1-go/internal/test/generatortest/generatortest.go @@ -6,9 +6,9 @@ import ( "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" "go.dedis.ch/kyber/v3/sign/schnorr" - "popstellar/crypto" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/crypto" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/lao.go b/be1-go/internal/test/generatortest/lao.go similarity index 97% rename from be1-go/internal/popserver/generatortest/lao.go rename to be1-go/internal/test/generatortest/lao.go index 80e035460c..49314d308b 100644 --- a/be1-go/internal/popserver/generatortest/lao.go +++ b/be1-go/internal/test/generatortest/lao.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/query.go b/be1-go/internal/test/generatortest/query.go similarity index 95% rename from be1-go/internal/popserver/generatortest/query.go rename to be1-go/internal/test/generatortest/query.go index 5e735a0969..10fb47fd0d 100644 --- a/be1-go/internal/popserver/generatortest/query.go +++ b/be1-go/internal/test/generatortest/query.go @@ -3,10 +3,10 @@ package generatortest import ( "encoding/json" "github.com/stretchr/testify/require" - jsonrpc "popstellar/message" - "popstellar/message/query" - "popstellar/message/query/method" - "popstellar/message/query/method/message" + jsonrpc "popstellar/internal/message" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/reaction.go b/be1-go/internal/test/generatortest/reaction.go similarity index 92% rename from be1-go/internal/popserver/generatortest/reaction.go rename to be1-go/internal/test/generatortest/reaction.go index abe494c0bf..03297460ef 100644 --- a/be1-go/internal/popserver/generatortest/reaction.go +++ b/be1-go/internal/test/generatortest/reaction.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/generatortest/root.go b/be1-go/internal/test/generatortest/root.go similarity index 86% rename from be1-go/internal/popserver/generatortest/root.go rename to be1-go/internal/test/generatortest/root.go index 8a60e2cfda..1bb4b3c3f4 100644 --- a/be1-go/internal/popserver/generatortest/root.go +++ b/be1-go/internal/test/generatortest/root.go @@ -4,8 +4,8 @@ import ( "encoding/json" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3" - "popstellar/message/messagedata" - "popstellar/message/query/method/message" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" "testing" ) diff --git a/be1-go/internal/popserver/types/hub_params.go b/be1-go/internal/types/hub_params.go similarity index 94% rename from be1-go/internal/popserver/types/hub_params.go rename to be1-go/internal/types/hub_params.go index 44debb1c7a..e4d49226a7 100644 --- a/be1-go/internal/popserver/types/hub_params.go +++ b/be1-go/internal/types/hub_params.go @@ -1,7 +1,7 @@ package types import ( - "popstellar/network/socket" + "popstellar/internal/network/socket" "sync" ) diff --git a/be1-go/internal/popserver/types/peers.go b/be1-go/internal/types/peers.go similarity index 95% rename from be1-go/internal/popserver/types/peers.go rename to be1-go/internal/types/peers.go index 41c7859591..37b2ba01a4 100644 --- a/be1-go/internal/popserver/types/peers.go +++ b/be1-go/internal/types/peers.go @@ -1,8 +1,8 @@ package types import ( - "popstellar/message/answer" - "popstellar/message/query/method" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" "sync" "golang.org/x/exp/maps" diff --git a/be1-go/internal/popserver/types/queries.go b/be1-go/internal/types/queries.go similarity index 98% rename from be1-go/internal/popserver/types/queries.go rename to be1-go/internal/types/queries.go index a56a6b842a..7c58c93956 100644 --- a/be1-go/internal/popserver/types/queries.go +++ b/be1-go/internal/types/queries.go @@ -1,7 +1,7 @@ package types import ( - "popstellar/message/query/method" + "popstellar/internal/message/query/method" "sync" "github.com/rs/zerolog" diff --git a/be1-go/internal/popserver/types/question.go b/be1-go/internal/types/question.go similarity index 100% rename from be1-go/internal/popserver/types/question.go rename to be1-go/internal/types/question.go diff --git a/be1-go/internal/popserver/types/sockets.go b/be1-go/internal/types/sockets.go similarity index 94% rename from be1-go/internal/popserver/types/sockets.go rename to be1-go/internal/types/sockets.go index 5f3d4c5b1a..aa76b45bfa 100644 --- a/be1-go/internal/popserver/types/sockets.go +++ b/be1-go/internal/types/sockets.go @@ -3,8 +3,8 @@ package types import ( "fmt" "math/rand" - "popstellar" - "popstellar/network/socket" + "popstellar/internal/logger" + "popstellar/internal/network/socket" "sync" ) @@ -83,7 +83,7 @@ func (s *Sockets) SendRumor(socket socket.Socket, senderID string, rumorID int, } if rState.counter >= len(s.store) { - popstellar.Logger.Debug().Msgf("stop sending rumor because completed cycle") + logger.Logger.Debug().Msgf("stop sending rumor because completed cycle") return } diff --git a/be1-go/internal/popserver/types/subscribers.go b/be1-go/internal/types/subscribers.go similarity index 96% rename from be1-go/internal/popserver/types/subscribers.go rename to be1-go/internal/types/subscribers.go index ab40671222..5ff06dd7ec 100644 --- a/be1-go/internal/popserver/types/subscribers.go +++ b/be1-go/internal/types/subscribers.go @@ -3,8 +3,8 @@ package types import ( "fmt" "golang.org/x/xerrors" - "popstellar/message/answer" - "popstellar/network/socket" + "popstellar/internal/message/answer" + "popstellar/internal/network/socket" "sync" ) diff --git a/be1-go/uint53/uint53.go b/be1-go/internal/types/uint53/uint53.go similarity index 100% rename from be1-go/uint53/uint53.go rename to be1-go/internal/types/uint53/uint53.go diff --git a/be1-go/uint53/uint53_test.go b/be1-go/internal/types/uint53/uint53_test.go similarity index 100% rename from be1-go/uint53/uint53_test.go rename to be1-go/internal/types/uint53/uint53_test.go diff --git a/be1-go/validation/schema_validator.go b/be1-go/internal/validation/schema_validator.go similarity index 98% rename from be1-go/validation/schema_validator.go rename to be1-go/internal/validation/schema_validator.go index 73978aa5f5..a014a2ebb8 100644 --- a/be1-go/validation/schema_validator.go +++ b/be1-go/internal/validation/schema_validator.go @@ -7,7 +7,7 @@ import ( "io" "io/fs" "path/filepath" - "popstellar/message/answer" + "popstellar/internal/message/answer" "strings" "github.com/santhosh-tekuri/jsonschema/v3" diff --git a/be1-go/validation/schema_validator_test.go b/be1-go/internal/validation/schema_validator_test.go similarity index 100% rename from be1-go/validation/schema_validator_test.go rename to be1-go/internal/validation/schema_validator_test.go diff --git a/be1-go/validation/validation.go b/be1-go/internal/validation/validation.go similarity index 100% rename from be1-go/validation/validation.go rename to be1-go/internal/validation/validation.go From 8ea9f2facbbb660527633b2f0d12e07dbd03639d Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 14:44:55 +0200 Subject: [PATCH 03/19] create a package for each type --- be1-go/internal/handler/channel_test.go | 2 +- be1-go/internal/handler/chirp_test.go | 13 ++- be1-go/internal/handler/coin_test.go | 11 ++- be1-go/internal/handler/election.go | 10 +- be1-go/internal/handler/election_test.go | 26 ++--- be1-go/internal/handler/federation_test.go | 43 +++++---- .../internal/handler/incoming_message_test.go | 8 +- be1-go/internal/handler/lao_test.go | 13 ++- be1-go/internal/handler/query_test.go | 95 ++++++++++--------- be1-go/internal/handler/reaction_test.go | 13 ++- be1-go/internal/handler/root_test.go | 17 ++-- .../{test => mock}/generatortest/chirp.go | 0 .../{test => mock}/generatortest/election.go | 0 .../generatortest/federation.go | 0 .../generatortest/generatortest.go | 0 .../{test => mock}/generatortest/lao.go | 0 .../{test => mock}/generatortest/query.go | 0 .../{test => mock}/generatortest/reaction.go | 0 .../{test => mock}/generatortest/root.go | 0 be1-go/internal/repository/mock_repository.go | 22 ++--- be1-go/internal/repository/repository.go | 6 +- be1-go/internal/singleton/state/state.go | 14 ++- be1-go/internal/sqlite/sqlite.go | 18 ++-- be1-go/internal/sqlite/sqlite_test.go | 72 +++++++------- .../internal/types/{ => election}/question.go | 2 +- .../types/{ => hubparams}/hub_params.go | 2 +- be1-go/internal/types/{ => peers}/peers.go | 2 +- .../internal/types/{ => queries}/queries.go | 2 +- .../internal/types/{ => sockets}/sockets.go | 2 +- .../types/{ => subscribers}/subscribers.go | 2 +- 30 files changed, 212 insertions(+), 183 deletions(-) rename be1-go/internal/{test => mock}/generatortest/chirp.go (100%) rename be1-go/internal/{test => mock}/generatortest/election.go (100%) rename be1-go/internal/{test => mock}/generatortest/federation.go (100%) rename be1-go/internal/{test => mock}/generatortest/generatortest.go (100%) rename be1-go/internal/{test => mock}/generatortest/lao.go (100%) rename be1-go/internal/{test => mock}/generatortest/query.go (100%) rename be1-go/internal/{test => mock}/generatortest/reaction.go (100%) rename be1-go/internal/{test => mock}/generatortest/root.go (100%) rename be1-go/internal/types/{ => election}/question.go (97%) rename be1-go/internal/types/{ => hubparams}/hub_params.go (97%) rename be1-go/internal/types/{ => peers}/peers.go (99%) rename be1-go/internal/types/{ => queries}/queries.go (99%) rename be1-go/internal/types/{ => sockets}/sockets.go (99%) rename be1-go/internal/types/{ => subscribers}/subscribers.go (99%) diff --git a/be1-go/internal/handler/channel_test.go b/be1-go/internal/handler/channel_test.go index 99544662ed..67f9a1dbec 100644 --- a/be1-go/internal/handler/channel_test.go +++ b/be1-go/internal/handler/channel_test.go @@ -7,9 +7,9 @@ import ( "golang.org/x/xerrors" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/database" - "popstellar/internal/test/generatortest" "testing" "time" ) diff --git a/be1-go/internal/handler/chirp_test.go b/be1-go/internal/handler/chirp_test.go index 8ed13cf84a..b11887567f 100644 --- a/be1-go/internal/handler/chirp_test.go +++ b/be1-go/internal/handler/chirp_test.go @@ -6,12 +6,15 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "strings" "testing" "time" @@ -19,9 +22,9 @@ import ( func Test_handleChannelChirp(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state2.SetState(subs, peers, queries, hubParams) diff --git a/be1-go/internal/handler/coin_test.go b/be1-go/internal/handler/coin_test.go index 58aa2d82a4..a3b1bb22bd 100644 --- a/be1-go/internal/handler/coin_test.go +++ b/be1-go/internal/handler/coin_test.go @@ -13,7 +13,10 @@ import ( "popstellar/internal/repository" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "testing" ) @@ -29,9 +32,9 @@ type inputTestHandleChannelCoin struct { func Test_handleChannelCoin(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state2.SetState(subs, peers, queries, hubParams) diff --git a/be1-go/internal/handler/election.go b/be1-go/internal/handler/election.go index 6dc0a8dc14..9f48937a41 100644 --- a/be1-go/internal/handler/election.go +++ b/be1-go/internal/handler/election.go @@ -12,7 +12,7 @@ import ( "popstellar/internal/message/query/method/message" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" - "popstellar/internal/types" + "popstellar/internal/types/election" "sort" ) @@ -391,7 +391,7 @@ func verifyVote(vote messagedata.Vote, channelPath, electionID string) *answer.E return nil } -func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[string]types.Question) *answer.Error { +func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[string]election.Question) *answer.Error { var voteIDs []string for _, question := range questions { for _, validVote := range question.ValidVotes { @@ -413,7 +413,7 @@ func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[st return nil } -func createElectionResult(questions map[string]types.Question, channelPath string) (message.Message, *answer.Error) { +func createElectionResult(questions map[string]election.Question, channelPath string) (message.Message, *answer.Error) { resultElection, errAnswer := computeElectionResult(questions, channelPath) if errAnswer != nil { return message.Message{}, errAnswer.Wrap("createElectionResult") @@ -453,7 +453,7 @@ func createElectionResult(questions map[string]types.Question, channelPath strin return electionResultMsg, nil } -func computeElectionResult(questions map[string]types.Question, channelPath string) ( +func computeElectionResult(questions map[string]election.Question, channelPath string) ( messagedata.ElectionResult, *answer.Error) { db, errAnswer := database.GetElectionRepositoryInstance() if errAnswer != nil { @@ -503,7 +503,7 @@ func computeElectionResult(questions map[string]types.Question, channelPath stri return resultElection, nil } -func getVoteIndex(vote types.ValidVote, electionType, channelPath string) (int, bool) { +func getVoteIndex(vote election.ValidVote, electionType, channelPath string) (int, bool) { switch electionType { case messagedata.OpenBallot: index, _ := vote.Index.(int) diff --git a/be1-go/internal/handler/election_test.go b/be1-go/internal/handler/election_test.go index afaa401042..c5bebfcd11 100644 --- a/be1-go/internal/handler/election_test.go +++ b/be1-go/internal/handler/election_test.go @@ -9,12 +9,16 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/election" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "testing" ) @@ -25,9 +29,9 @@ func Test_handleChannelElection(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() ownerPubBuf, err := base64.URLEncoding.DecodeString(ownerPubBuf64) require.NoError(t, err) @@ -278,7 +282,7 @@ func Test_handleChannelElection(t *testing.T) { channelPath = "/root/" + laoID + "/" + electionID //Test 18 Error when VoteCastVote question is not present in election setup - questions := map[string]types2.Question{ + questions := map[string]election.Question{ base64.URLEncoding.EncodeToString([]byte("questionID2")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID2")))}, base64.URLEncoding.EncodeToString([]byte("questionID3")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID3")))}, } @@ -445,10 +449,10 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } if votes != "" { - questions := map[string]types2.Question{ + questions := map[string]election.Question{ "questionID1": { ID: []byte("questionID1"), - ValidVotes: map[string]types2.ValidVote{ + ValidVotes: map[string]election.ValidVote{ "voteID1": { ID: "voteID1", }, @@ -459,7 +463,7 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI }, "questionID2": { ID: []byte("questionID2"), - ValidVotes: map[string]types2.ValidVote{ + ValidVotes: map[string]election.ValidVote{ "voteID3": { ID: "voteID3", }, @@ -480,7 +484,7 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath, state, electionType string, - createdAt int64, votes []generatortest.VoteInt, questions map[string]types2.Question, owner kyber.Point, + createdAt int64, votes []generatortest.VoteInt, questions map[string]election.Question, owner kyber.Point, mockRepository *repository.MockRepository, isEroor bool) message.Message { msg := generatortest.NewVoteCastVoteIntMsg(t, sender, laoID, electionID, 1, votes, nil) @@ -518,7 +522,7 @@ func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath } func newVoteCastVoteStringMsg(t *testing.T, sender, laoID, electionID, electionPath, electionType string, - createdAt int64, votes []generatortest.VoteString, questions map[string]types2.Question, owner kyber.Point, + createdAt int64, votes []generatortest.VoteString, questions map[string]election.Question, owner kyber.Point, mockRepository *repository.MockRepository) message.Message { msg := generatortest.NewVoteCastVoteStringMsg(t, sender, laoID, electionID, 1, votes, nil) diff --git a/be1-go/internal/handler/federation_test.go b/be1-go/internal/handler/federation_test.go index 74fad3e881..eb0d100f43 100644 --- a/be1-go/internal/handler/federation_test.go +++ b/be1-go/internal/handler/federation_test.go @@ -13,13 +13,16 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query" "popstellar/internal/message/query/method" + "popstellar/internal/mock/generatortest" "popstellar/internal/network/socket" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "testing" "time" ) @@ -31,9 +34,9 @@ func Test_handleChannelFederation(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -322,9 +325,9 @@ func Test_handleRequestChallenge(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -378,9 +381,9 @@ func Test_handleFederationExpect(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -438,9 +441,9 @@ func Test_handleFederationInit(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -521,9 +524,9 @@ func Test_handleFederationChallenge(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -628,9 +631,9 @@ func Test_handleFederationResult(t *testing.T) { database.SetDatabase(mockRepository) subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() organizerPk, organizerSk := generateKeys() organizer2Pk, organizer2Sk := generateKeys() diff --git a/be1-go/internal/handler/incoming_message_test.go b/be1-go/internal/handler/incoming_message_test.go index f022405fc8..25f30f65e6 100644 --- a/be1-go/internal/handler/incoming_message_test.go +++ b/be1-go/internal/handler/incoming_message_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" "io" "os" + "popstellar/internal/mock/generatortest" "popstellar/internal/network/socket" "popstellar/internal/singleton/utils" - generatortest2 "popstellar/internal/test/generatortest" "popstellar/internal/validation" "testing" ) @@ -43,18 +43,18 @@ func Test_handleIncomingMessage(t *testing.T) { args = append(args, input{ name: "Test 1", - message: generatortest2.NewNothingQuery(t, 999), + message: generatortest.NewNothingQuery(t, 999), contains: "invalid json", }) // Test 2: failed to handled popanswer because wrong publish popanswer format - msg := generatortest2.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) + msg := generatortest.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) msg.MessageID = "wrong messageID" args = append(args, input{ name: "Test 2", - message: generatortest2.NewPublishQuery(t, 1, "/root/lao1", msg), + message: generatortest.NewPublishQuery(t, 1, "/root/lao1", msg), contains: "invalid json", }) diff --git a/be1-go/internal/handler/lao_test.go b/be1-go/internal/handler/lao_test.go index d4ae42d9b5..4cb40d5bd0 100644 --- a/be1-go/internal/handler/lao_test.go +++ b/be1-go/internal/handler/lao_test.go @@ -8,12 +8,15 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "strconv" "strings" "testing" @@ -22,9 +25,9 @@ import ( func Test_handleChannelLao(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) diff --git a/be1-go/internal/handler/query_test.go b/be1-go/internal/handler/query_test.go index 3f1e496b2f..4f3c8122fd 100644 --- a/be1-go/internal/handler/query_test.go +++ b/be1-go/internal/handler/query_test.go @@ -7,13 +7,16 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/network/socket" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - generatortest2 "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "testing" ) @@ -28,7 +31,7 @@ func Test_handleQuery(t *testing.T) { // Test 1: failed to handled popquery because unknown method - msg := generatortest2.NewNothingQuery(t, 999) + msg := generatortest.NewNothingQuery(t, 999) args = append(args, input{ name: "Test 1", @@ -50,9 +53,9 @@ func Test_handleQuery(t *testing.T) { func Test_handleGreetServer(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -72,7 +75,7 @@ func Test_handleGreetServer(t *testing.T) { args := make([]input, 0) - greetServer := generatortest2.NewGreetServerQuery(t, "pk", "client", "server") + greetServer := generatortest.NewGreetServerQuery(t, "pk", "client", "server") // Test 1: reply with greet server when receiving a greet server from a new server @@ -137,9 +140,9 @@ func Test_handleGreetServer(t *testing.T) { func Test_handleSubscribe(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -169,7 +172,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewSubscribeQuery(t, ID, channel), + message: generatortest.NewSubscribeQuery(t, ID, channel), isError: false, }) @@ -184,7 +187,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewSubscribeQuery(t, ID, channel), + message: generatortest.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to unknown channel", }) @@ -200,7 +203,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewSubscribeQuery(t, ID, channel), + message: generatortest.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to root channel", }) @@ -226,9 +229,9 @@ func Test_handleSubscribe(t *testing.T) { func Test_handleUnsubscribe(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -261,7 +264,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewUnsubscribeQuery(t, ID, channel), + message: generatortest.NewUnsubscribeQuery(t, ID, channel), isError: false, }) @@ -279,7 +282,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewUnsubscribeQuery(t, ID, channel), + message: generatortest.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from a channel not subscribed", }) @@ -295,7 +298,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewUnsubscribeQuery(t, ID, channel), + message: generatortest.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from unknown channel", }) @@ -311,7 +314,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest2.NewUnsubscribeQuery(t, ID, channel), + message: generatortest.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from root channel", }) @@ -338,9 +341,9 @@ func Test_handleUnsubscribe(t *testing.T) { func Test_handleCatchUp(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -365,10 +368,10 @@ func Test_handleCatchUp(t *testing.T) { ID := 1 channel := "/root/lao1" messagesToCatchUp := []message.Message{ - generatortest2.NewNothingMsg(t, "sender1", nil), - generatortest2.NewNothingMsg(t, "sender2", nil), - generatortest2.NewNothingMsg(t, "sender3", nil), - generatortest2.NewNothingMsg(t, "sender4", nil), + generatortest.NewNothingMsg(t, "sender1", nil), + generatortest.NewNothingMsg(t, "sender2", nil), + generatortest.NewNothingMsg(t, "sender3", nil), + generatortest.NewNothingMsg(t, "sender4", nil), } mockRepository.On("GetAllMessagesFromChannel", channel).Return(messagesToCatchUp, nil) @@ -377,7 +380,7 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest2.NewCatchupQuery(t, ID, channel), + message: generatortest.NewCatchupQuery(t, ID, channel), expected: messagesToCatchUp, isError: false, }) @@ -395,7 +398,7 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest2.NewCatchupQuery(t, ID, channel), + message: generatortest.NewCatchupQuery(t, ID, channel), isError: true, contains: "DB is disconnected", }) @@ -420,9 +423,9 @@ func Test_handleCatchUp(t *testing.T) { func Test_handleHeartbeat(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -475,7 +478,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 1", socket: fakeSocket, - message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs1), + message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs1), expected: expected1, isError: false, }) @@ -496,7 +499,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 2", socket: fakeSocket, - message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs2), + message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs2), isError: false, }) @@ -521,7 +524,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "failed to popquery DB", socket: fakeSocket, - message: generatortest2.NewHeartbeatQuery(t, heartbeatMsgIDs3), + message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs3), isError: true, contains: "DB is disconnected", }) @@ -552,9 +555,9 @@ func Test_handleHeartbeat(t *testing.T) { func Test_handleGetMessagesByID(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -580,14 +583,14 @@ func Test_handleGetMessagesByID(t *testing.T) { expected1 := make(map[string][]message.Message) expected1["/root"] = []message.Message{ - generatortest2.NewNothingMsg(t, "sender1", nil), - generatortest2.NewNothingMsg(t, "sender2", nil), - generatortest2.NewNothingMsg(t, "sender3", nil), - generatortest2.NewNothingMsg(t, "sender4", nil), + generatortest.NewNothingMsg(t, "sender1", nil), + generatortest.NewNothingMsg(t, "sender2", nil), + generatortest.NewNothingMsg(t, "sender3", nil), + generatortest.NewNothingMsg(t, "sender4", nil), } expected1["/root/lao1"] = []message.Message{ - generatortest2.NewNothingMsg(t, "sender5", nil), - generatortest2.NewNothingMsg(t, "sender6", nil), + generatortest.NewNothingMsg(t, "sender5", nil), + generatortest.NewNothingMsg(t, "sender6", nil), } paramsGetMessagesByID1 := make(map[string][]string) @@ -604,7 +607,7 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest2.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), + message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), expected: expected1, isError: false, }) @@ -623,7 +626,7 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest2.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), + message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), isError: true, contains: "DB is disconnected", }) diff --git a/be1-go/internal/handler/reaction_test.go b/be1-go/internal/handler/reaction_test.go index fcf261708b..5c784d1e0d 100644 --- a/be1-go/internal/handler/reaction_test.go +++ b/be1-go/internal/handler/reaction_test.go @@ -5,12 +5,15 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "strings" "testing" "time" @@ -18,9 +21,9 @@ import ( func Test_handleChannelReaction(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state2.SetState(subs, peers, queries, hubParams) diff --git a/be1-go/internal/handler/root_test.go b/be1-go/internal/handler/root_test.go index 7df52fe755..0299cf3d5d 100644 --- a/be1-go/internal/handler/root_test.go +++ b/be1-go/internal/handler/root_test.go @@ -8,13 +8,16 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" + "popstellar/internal/mock/generatortest" "popstellar/internal/repository" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" "popstellar/internal/sqlite" - generatortest2 "popstellar/internal/test/generatortest" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + peers2 "popstellar/internal/types/peers" + queries2 "popstellar/internal/types/queries" + types2 "popstellar/internal/types/subscribers" "testing" "time" ) @@ -36,9 +39,9 @@ type input struct { func Test_handleChannelRoot(t *testing.T) { subs := types2.NewSubscribers() - queries := types2.NewQueries(&noLog) - peers := types2.NewPeers() - hubParams := types2.NewHubParams() + queries := queries2.NewQueries(&noLog) + peers := peers2.NewPeers() + hubParams := hubparams.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -89,7 +92,7 @@ func Test_handleChannelRoot(t *testing.T) { // Test 4: error when message data is not lao_create args = append(args, input{ name: "Test 4", - msg: generatortest2.NewNothingMsg(t, owner, nil), + msg: generatortest.NewNothingMsg(t, owner, nil), isError: true, contains: "failed to validate schema", }) @@ -123,7 +126,7 @@ func newLaoCreateMsg(t *testing.T, organizer, sender, laoName string, mockReposi goodLaoName, ) - msg := generatortest2.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) + msg := generatortest.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) mockRepository.On("HasChannel", RootPrefix+laoID).Return(false, nil) if !isError { diff --git a/be1-go/internal/test/generatortest/chirp.go b/be1-go/internal/mock/generatortest/chirp.go similarity index 100% rename from be1-go/internal/test/generatortest/chirp.go rename to be1-go/internal/mock/generatortest/chirp.go diff --git a/be1-go/internal/test/generatortest/election.go b/be1-go/internal/mock/generatortest/election.go similarity index 100% rename from be1-go/internal/test/generatortest/election.go rename to be1-go/internal/mock/generatortest/election.go diff --git a/be1-go/internal/test/generatortest/federation.go b/be1-go/internal/mock/generatortest/federation.go similarity index 100% rename from be1-go/internal/test/generatortest/federation.go rename to be1-go/internal/mock/generatortest/federation.go diff --git a/be1-go/internal/test/generatortest/generatortest.go b/be1-go/internal/mock/generatortest/generatortest.go similarity index 100% rename from be1-go/internal/test/generatortest/generatortest.go rename to be1-go/internal/mock/generatortest/generatortest.go diff --git a/be1-go/internal/test/generatortest/lao.go b/be1-go/internal/mock/generatortest/lao.go similarity index 100% rename from be1-go/internal/test/generatortest/lao.go rename to be1-go/internal/mock/generatortest/lao.go diff --git a/be1-go/internal/test/generatortest/query.go b/be1-go/internal/mock/generatortest/query.go similarity index 100% rename from be1-go/internal/test/generatortest/query.go rename to be1-go/internal/mock/generatortest/query.go diff --git a/be1-go/internal/test/generatortest/reaction.go b/be1-go/internal/mock/generatortest/reaction.go similarity index 100% rename from be1-go/internal/test/generatortest/reaction.go rename to be1-go/internal/mock/generatortest/reaction.go diff --git a/be1-go/internal/test/generatortest/root.go b/be1-go/internal/mock/generatortest/root.go similarity index 100% rename from be1-go/internal/test/generatortest/root.go rename to be1-go/internal/mock/generatortest/root.go diff --git a/be1-go/internal/repository/mock_repository.go b/be1-go/internal/repository/mock_repository.go index f6233c3280..1ad704d2df 100644 --- a/be1-go/internal/repository/mock_repository.go +++ b/be1-go/internal/repository/mock_repository.go @@ -5,7 +5,7 @@ package repository import ( messagedata "popstellar/internal/message/messagedata" message "popstellar/internal/message/query/method/message" - "popstellar/internal/types" + "popstellar/internal/types/election" kyber "go.dedis.ch/kyber/v3" @@ -283,23 +283,23 @@ func (_m *MockRepository) GetElectionCreationTime(electionID string) (int64, err } // GetElectionQuestions provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionQuestions(electionID string) (map[string]types.Question, error) { +func (_m *MockRepository) GetElectionQuestions(electionID string) (map[string]election.Question, error) { ret := _m.Called(electionID) if len(ret) == 0 { panic("no return value specified for GetElectionQuestions") } - var r0 map[string]types.Question + var r0 map[string]election.Question var r1 error - if rf, ok := ret.Get(0).(func(string) (map[string]types.Question, error)); ok { + if rf, ok := ret.Get(0).(func(string) (map[string]election.Question, error)); ok { return rf(electionID) } - if rf, ok := ret.Get(0).(func(string) map[string]types.Question); ok { + if rf, ok := ret.Get(0).(func(string) map[string]election.Question); ok { r0 = rf(electionID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]types.Question) + r0 = ret.Get(0).(map[string]election.Question) } } @@ -313,23 +313,23 @@ func (_m *MockRepository) GetElectionQuestions(electionID string) (map[string]ty } // GetElectionQuestionsWithValidVotes provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionQuestionsWithValidVotes(electionID string) (map[string]types.Question, error) { +func (_m *MockRepository) GetElectionQuestionsWithValidVotes(electionID string) (map[string]election.Question, error) { ret := _m.Called(electionID) if len(ret) == 0 { panic("no return value specified for GetElectionQuestionsWithValidVotes") } - var r0 map[string]types.Question + var r0 map[string]election.Question var r1 error - if rf, ok := ret.Get(0).(func(string) (map[string]types.Question, error)); ok { + if rf, ok := ret.Get(0).(func(string) (map[string]election.Question, error)); ok { return rf(electionID) } - if rf, ok := ret.Get(0).(func(string) map[string]types.Question); ok { + if rf, ok := ret.Get(0).(func(string) map[string]election.Question); ok { r0 = rf(electionID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]types.Question) + r0 = ret.Get(0).(map[string]election.Question) } } diff --git a/be1-go/internal/repository/repository.go b/be1-go/internal/repository/repository.go index caa1541e48..6c0a23020b 100644 --- a/be1-go/internal/repository/repository.go +++ b/be1-go/internal/repository/repository.go @@ -5,7 +5,7 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/types" + "popstellar/internal/types/election" ) type Repository interface { @@ -169,10 +169,10 @@ type ElectionRepository interface { GetElectionAttendees(electionID string) (map[string]struct{}, error) // GetElectionQuestions returns the questions of an election. - GetElectionQuestions(electionID string) (map[string]types.Question, error) + GetElectionQuestions(electionID string) (map[string]election.Question, error) // GetElectionQuestionsWithValidVotes returns the questions of an election with valid votes. - GetElectionQuestionsWithValidVotes(electionID string) (map[string]types.Question, error) + GetElectionQuestionsWithValidVotes(electionID string) (map[string]election.Question, error) // StoreElectionEndWithResult stores a message and an election result message inside the database. StoreElectionEndWithResult(channelID string, msg, electionResultMsg message.Message) error diff --git a/be1-go/internal/singleton/state/state.go b/be1-go/internal/singleton/state/state.go index d61a881712..26103ed61c 100644 --- a/be1-go/internal/singleton/state/state.go +++ b/be1-go/internal/singleton/state/state.go @@ -3,7 +3,11 @@ package state import ( "github.com/rs/zerolog" "popstellar/internal/message/answer" - types2 "popstellar/internal/types" + "popstellar/internal/types/hubparams" + "popstellar/internal/types/peers" + "popstellar/internal/types/queries" + "popstellar/internal/types/sockets" + types2 "popstellar/internal/types/subscribers" "sync" ) @@ -23,10 +27,10 @@ func InitState(log *zerolog.Logger) { once.Do(func() { instance = &state{ subs: types2.NewSubscribers(), - peers: types2.NewPeers(), - queries: types2.NewQueries(log), - hubParams: types2.NewHubParams(), - sockets: types2.NewSockets(), + peers: peers.NewPeers(), + queries: queries.NewQueries(log), + hubParams: hubparams.NewHubParams(), + sockets: sockets.NewSockets(), resetRumorSender: make(chan struct{}), } }) diff --git a/be1-go/internal/sqlite/sqlite.go b/be1-go/internal/sqlite/sqlite.go index fe9709205a..9ed760b6ac 100644 --- a/be1-go/internal/sqlite/sqlite.go +++ b/be1-go/internal/sqlite/sqlite.go @@ -14,7 +14,7 @@ import ( "popstellar/internal/message/query" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/types" + "popstellar/internal/types/election" "strings" "time" ) @@ -1008,7 +1008,7 @@ func (s *SQLite) getElectionSetup(electionPath string, tx *sql.Tx) (messagedata. } -func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]types.Question, error) { +func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]election.Question, error) { dbLock.Lock() defer dbLock.Unlock() @@ -1037,7 +1037,7 @@ func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]types.Que return questions, nil } -func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[string]types.Question, error) { +func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[string]election.Question, error) { dbLock.Lock() defer dbLock.Unlock() @@ -1089,8 +1089,8 @@ func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[st return questions, nil } -func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[string]types.Question, error) { - questions := make(map[string]types.Question) +func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[string]election.Question, error) { + questions := make(map[string]election.Question) for _, question := range electionSetup.Questions { ballotOptions := make([]string, len(question.BallotOptions)) copy(ballotOptions, question.BallotOptions) @@ -1098,17 +1098,17 @@ func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[strin if ok { return nil, xerrors.Errorf("duplicate question ID") } - questions[question.ID] = types.Question{ + questions[question.ID] = election.Question{ ID: []byte(question.ID), BallotOptions: ballotOptions, - ValidVotes: make(map[string]types.ValidVote), + ValidVotes: make(map[string]election.ValidVote), Method: question.VotingMethod, } } return questions, nil } -func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questions map[string]types.Question) error { +func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questions map[string]election.Question) error { for idx, vote := range castVote.Votes { question, ok := questions[vote.Question] if !ok { @@ -1116,7 +1116,7 @@ func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questio } earlierVote, ok := question.ValidVotes[sender] if !ok || earlierVote.VoteTime < castVote.CreatedAt { - question.ValidVotes[sender] = types.ValidVote{ + question.ValidVotes[sender] = election.ValidVote{ MsgID: msgID, ID: vote.ID, VoteTime: castVote.CreatedAt, diff --git a/be1-go/internal/sqlite/sqlite_test.go b/be1-go/internal/sqlite/sqlite_test.go index fddb850ed2..6f8baba962 100644 --- a/be1-go/internal/sqlite/sqlite_test.go +++ b/be1-go/internal/sqlite/sqlite_test.go @@ -11,8 +11,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - generatortest2 "popstellar/internal/test/generatortest" - "popstellar/internal/types" + "popstellar/internal/mock/generatortest" + "popstellar/internal/types/election" "sort" "testing" "time" @@ -318,7 +318,7 @@ func Test_SQLite_StoreLaoWithLaoGreet(t *testing.T) { laoID := "laoID" - laoCreateMsg := generatortest2.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, + laoCreateMsg := generatortest.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, organizerPubBuf64, nil) laoGreet := messagedata.LaoGreet{ @@ -389,9 +389,9 @@ func Test_SQLite_GetRollCallState(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest2.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallOpen := generatortest2.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) states := []string{"create", "open", "close"} messages := []message.Message{rollCallCreate, rollCallOpen, rollCallClose} @@ -410,8 +410,8 @@ func Test_SQLite_CheckPrevOpenOrReopenID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallOpen := generatortest2.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallReopen := generatortest2.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) + rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallReopen := generatortest.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) err = lite.StoreMessageAndData("channel1", rollCallOpen) require.NoError(t, err) @@ -434,8 +434,8 @@ func Test_SQLite_CheckPrevCreateOrCloseID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest2.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreMessageAndData("channel1", rollCallCreate) require.NoError(t, err) @@ -461,7 +461,7 @@ func Test_SQLite_StoreRollCallClose(t *testing.T) { channels := []string{"channel1", "channel2", "channel3"} laoID := "laoID" - rollCallClose := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreRollCallClose(channels, laoID, rollCallClose) require.NoError(t, err) @@ -492,7 +492,7 @@ func Test_SQLite_StoreElectionWithElectionKey(t *testing.T) { electionPubBuf, err := point.MarshalBinary() require.NoError(t, err) - electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) electionKey := messagedata.ElectionKey{ @@ -542,7 +542,7 @@ func Test_SQLite_StoreElection(t *testing.T) { secret := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) point := crypto.Suite.Point().Mul(secret, nil) - electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) err = lite.StoreElection(laoID, electionID, point, secret, electionSetupMsg) @@ -576,7 +576,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionOpenMsg := generatortest2.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) + electionOpenMsg := generatortest.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) err = lite.StoreMessageAndData(electionID, electionOpenMsg) require.NoError(t, err) @@ -592,7 +592,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionCloseMsg := generatortest2.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionCloseMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) err = lite.StoreMessageAndData(electionID, electionCloseMsg) require.NoError(t, err) @@ -619,7 +619,7 @@ func Test_SQLite_GetElectionCreationTimeAndType(t *testing.T) { electionPath := "electionPath" creationTime := int64(123456789) - electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, creationTime, 2, 3, nil, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -645,7 +645,7 @@ func Test_SQLite_GetElectionAttendees(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} expected := map[string]struct{}{"attendee1": {}, "attendee2": {}, "attendee3": {}} - rollCallCloseMsg := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) + rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) require.NoError(t, err) @@ -677,7 +677,7 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { }, } - electionSetupMsg := generatortest2.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, 1, 2, 3, questions, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -694,16 +694,16 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.NoError(t, err) // Add votes to the election - vote1 := generatortest2.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} - votes := []generatortest2.VoteString{vote1} - castVoteMsg := generatortest2.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote1 := generatortest.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} + votes := []generatortest.VoteString{vote1} + castVoteMsg := generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 1, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) require.NoError(t, err) question1 := expected["questionID1"] - question1.ValidVotes = map[string]types.ValidVote{ + question1.ValidVotes = map[string]election.ValidVote{ "sender1": {MsgID: castVoteMsg.MessageID, ID: "voteID1", VoteTime: 1, Index: "Option1"}, } expected["questionID1"] = question1 @@ -713,16 +713,16 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.Equal(t, expected, result) // Add more votes to the election - vote2 := generatortest2.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} - votes = []generatortest2.VoteString{vote2} - castVoteMsg = generatortest2.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote2 := generatortest.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} + votes = []generatortest.VoteString{vote2} + castVoteMsg = generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 2, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) require.NoError(t, err) question1 = expected["questionID1"] - question1.ValidVotes = map[string]types.ValidVote{ + question1.ValidVotes = map[string]election.ValidVote{ "sender1": {MsgID: castVoteMsg.MessageID, ID: "voteID2", VoteTime: 2, Index: "Option2"}, } expected["questionID1"] = question1 @@ -742,8 +742,8 @@ func Test_SQLite_StoreElectionEndWithResult(t *testing.T) { laoID := "laoID" electionID := "electionID" - electionEndMsg := generatortest2.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) - electionResultMsg := generatortest2.NewElectionResultMsg(t, "sender2", nil, nil) + electionEndMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionResultMsg := generatortest.NewElectionResultMsg(t, "sender2", nil, nil) err = lite.StoreElectionEndWithResult(electionPath, electionEndMsg, electionResultMsg) require.NoError(t, err) @@ -763,7 +763,7 @@ func Test_SQLite_StoreChirpMessages(t *testing.T) { chirpPath := "chirpID" generalChirpPath := "generalChirpID" - chirpMsg := generatortest2.NewChirpAddMsg(t, "sender1", nil, 1) + chirpMsg := generatortest.NewChirpAddMsg(t, "sender1", nil, 1) generalChirpMsg := message.Message{ Data: base64.URLEncoding.EncodeToString([]byte("data")), Sender: "sender1", @@ -795,7 +795,7 @@ func Test_SQLite_IsAttendee(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} laoID := "laoID" - rollCallCloseMsg := generatortest2.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", + rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) @@ -817,7 +817,7 @@ func Test_SQLite_GetReactionSender(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - reactionAddMsg := generatortest2.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) + reactionAddMsg := generatortest.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) sender, err := lite.GetReactionSender(reactionAddMsg.MessageID) require.NoError(t, err) @@ -849,7 +849,7 @@ func Test_SQLite_IsChallengeValid(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest2.NewFederationChallenge(t, sender, value, + challengeMsg := generatortest.NewFederationChallenge(t, sender, value, validUntil, nil) err = lite.StoreMessageAndData(fedPath, challengeMsg) @@ -894,10 +894,10 @@ func Test_SQLite_GetFederationExpect(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest2.NewFederationChallenge(t, organizer, value, + challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest2.NewFederationExpect(t, organizer, laoId, + expectMsg := generatortest.NewFederationExpect(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationExpect(organizer, organizer2, challenge, fedPath) @@ -940,10 +940,10 @@ func Test_SQLite_GetFederationInit(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest2.NewFederationChallenge(t, organizer, value, + challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest2.NewFederationInit(t, organizer, laoId, + expectMsg := generatortest.NewFederationInit(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationInit(organizer, organizer2, challenge, fedPath) diff --git a/be1-go/internal/types/question.go b/be1-go/internal/types/election/question.go similarity index 97% rename from be1-go/internal/types/question.go rename to be1-go/internal/types/election/question.go index c44f5e222d..4710116b21 100644 --- a/be1-go/internal/types/question.go +++ b/be1-go/internal/types/election/question.go @@ -1,4 +1,4 @@ -package types +package election type Question struct { // ID represents the ID of the Question. diff --git a/be1-go/internal/types/hub_params.go b/be1-go/internal/types/hubparams/hub_params.go similarity index 97% rename from be1-go/internal/types/hub_params.go rename to be1-go/internal/types/hubparams/hub_params.go index e4d49226a7..449dbdf408 100644 --- a/be1-go/internal/types/hub_params.go +++ b/be1-go/internal/types/hubparams/hub_params.go @@ -1,4 +1,4 @@ -package types +package hubparams import ( "popstellar/internal/network/socket" diff --git a/be1-go/internal/types/peers.go b/be1-go/internal/types/peers/peers.go similarity index 99% rename from be1-go/internal/types/peers.go rename to be1-go/internal/types/peers/peers.go index 37b2ba01a4..88ec7695bf 100644 --- a/be1-go/internal/types/peers.go +++ b/be1-go/internal/types/peers/peers.go @@ -1,4 +1,4 @@ -package types +package peers import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/types/queries.go b/be1-go/internal/types/queries/queries.go similarity index 99% rename from be1-go/internal/types/queries.go rename to be1-go/internal/types/queries/queries.go index 7c58c93956..07bed48ea5 100644 --- a/be1-go/internal/types/queries.go +++ b/be1-go/internal/types/queries/queries.go @@ -1,4 +1,4 @@ -package types +package queries import ( "popstellar/internal/message/query/method" diff --git a/be1-go/internal/types/sockets.go b/be1-go/internal/types/sockets/sockets.go similarity index 99% rename from be1-go/internal/types/sockets.go rename to be1-go/internal/types/sockets/sockets.go index aa76b45bfa..a4d6b761ab 100644 --- a/be1-go/internal/types/sockets.go +++ b/be1-go/internal/types/sockets/sockets.go @@ -1,4 +1,4 @@ -package types +package sockets import ( "fmt" diff --git a/be1-go/internal/types/subscribers.go b/be1-go/internal/types/subscribers/subscribers.go similarity index 99% rename from be1-go/internal/types/subscribers.go rename to be1-go/internal/types/subscribers/subscribers.go index 5ff06dd7ec..6c89139028 100644 --- a/be1-go/internal/types/subscribers.go +++ b/be1-go/internal/types/subscribers/subscribers.go @@ -1,4 +1,4 @@ -package types +package subscribers import ( "fmt" From c00de9ab398d1177794d70910940a809f4bb5317 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 15:05:16 +0200 Subject: [PATCH 04/19] create package mocks --- .../{docs => docsutils}/depgraph/README.md | 0 .../{docs => docsutils}/depgraph/dep.yml | 4 +- .../{docs => docsutils}/depgraph/depgraph.go | 0 be1-go/internal/handler/answer_test.go | 4 +- be1-go/internal/handler/channel_test.go | 28 +-- be1-go/internal/handler/chirp_test.go | 27 ++- be1-go/internal/handler/coin_test.go | 24 ++- be1-go/internal/handler/election.go | 10 +- be1-go/internal/handler/election_test.go | 56 +++--- be1-go/internal/handler/federation_test.go | 164 +++++++++--------- .../internal/handler/incoming_message_test.go | 12 +- be1-go/internal/handler/lao_test.go | 39 ++--- be1-go/internal/handler/query_test.go | 164 +++++++++--------- be1-go/internal/handler/reaction_test.go | 27 ++- be1-go/internal/handler/root_test.go | 25 ++- .../messagedata/coin_post_transaction.go | 12 +- .../{network/socket => mocks}/fake_socket.go | 13 +- .../generator}/chirp.go | 2 +- .../generator}/election.go | 2 +- .../generator}/federation.go | 2 +- .../generator}/generatortest.go | 2 +- .../generatortest => mocks/generator}/lao.go | 2 +- .../generator}/query.go | 2 +- .../generator}/reaction.go | 2 +- .../generatortest => mocks/generator}/root.go | 2 +- .../repository.go} | 121 ++++++------- be1-go/internal/repository/repository.go | 6 +- .../internal/singleton/database/database.go | 3 +- be1-go/internal/singleton/state/state.go | 16 +- be1-go/internal/sqlite/sqlite.go | 18 +- be1-go/internal/sqlite/sqlite_test.go | 72 ++++---- .../types/{hubparams => }/hub_params.go | 2 +- be1-go/internal/types/{peers => }/peers.go | 2 +- .../internal/types/{queries => }/queries.go | 2 +- .../internal/types/{election => }/question.go | 2 +- .../internal/types/{sockets => }/sockets.go | 2 +- .../types/{subscribers => }/subscribers.go | 2 +- be1-go/internal/types/{uint53 => }/uint53.go | 2 +- .../types/{uint53 => }/uint53_test.go | 2 +- 39 files changed, 425 insertions(+), 452 deletions(-) rename be1-go/internal/{docs => docsutils}/depgraph/README.md (100%) rename be1-go/internal/{docs => docsutils}/depgraph/dep.yml (56%) rename be1-go/internal/{docs => docsutils}/depgraph/depgraph.go (100%) rename be1-go/internal/{network/socket => mocks}/fake_socket.go (78%) rename be1-go/internal/{mock/generatortest => mocks/generator}/chirp.go (97%) rename be1-go/internal/{mock/generatortest => mocks/generator}/election.go (99%) rename be1-go/internal/{mock/generatortest => mocks/generator}/federation.go (99%) rename be1-go/internal/{mock/generatortest => mocks/generator}/generatortest.go (98%) rename be1-go/internal/{mock/generatortest => mocks/generator}/lao.go (99%) rename be1-go/internal/{mock/generatortest => mocks/generator}/query.go (99%) rename be1-go/internal/{mock/generatortest => mocks/generator}/reaction.go (98%) rename be1-go/internal/{mock/generatortest => mocks/generator}/root.go (96%) rename be1-go/internal/{repository/mock_repository.go => mocks/repository.go} (82%) rename be1-go/internal/types/{hubparams => }/hub_params.go (97%) rename be1-go/internal/types/{peers => }/peers.go (99%) rename be1-go/internal/types/{queries => }/queries.go (99%) rename be1-go/internal/types/{election => }/question.go (97%) rename be1-go/internal/types/{sockets => }/sockets.go (99%) rename be1-go/internal/types/{subscribers => }/subscribers.go (99%) rename be1-go/internal/types/{uint53 => }/uint53.go (98%) rename be1-go/internal/types/{uint53 => }/uint53_test.go (98%) diff --git a/be1-go/internal/docs/depgraph/README.md b/be1-go/internal/docsutils/depgraph/README.md similarity index 100% rename from be1-go/internal/docs/depgraph/README.md rename to be1-go/internal/docsutils/depgraph/README.md diff --git a/be1-go/internal/docs/depgraph/dep.yml b/be1-go/internal/docsutils/depgraph/dep.yml similarity index 56% rename from be1-go/internal/docs/depgraph/dep.yml rename to be1-go/internal/docsutils/depgraph/dep.yml index 200f58f5ff..203115d77c 100644 --- a/be1-go/internal/docs/depgraph/dep.yml +++ b/be1-go/internal/docsutils/depgraph/dep.yml @@ -2,7 +2,7 @@ modname: popstellar overwrite: true outfile: graph.dot includes: - - popstellar/internal/popserver/* - - popstellar/network/socket + - popstellar/internal/* excludes: + - popstellar/internal/docsutils interfaces: diff --git a/be1-go/internal/docs/depgraph/depgraph.go b/be1-go/internal/docsutils/depgraph/depgraph.go similarity index 100% rename from be1-go/internal/docs/depgraph/depgraph.go rename to be1-go/internal/docsutils/depgraph/depgraph.go diff --git a/be1-go/internal/handler/answer_test.go b/be1-go/internal/handler/answer_test.go index bfca1313b8..7026b7cdad 100644 --- a/be1-go/internal/handler/answer_test.go +++ b/be1-go/internal/handler/answer_test.go @@ -9,14 +9,14 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/repository" + "popstellar/internal/mocks" "popstellar/internal/singleton/database" "testing" "time" ) func Test_handleMessagesByChannel(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) type input struct { diff --git a/be1-go/internal/handler/channel_test.go b/be1-go/internal/handler/channel_test.go index 67f9a1dbec..7e4df3eeda 100644 --- a/be1-go/internal/handler/channel_test.go +++ b/be1-go/internal/handler/channel_test.go @@ -7,8 +7,8 @@ import ( "golang.org/x/xerrors" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/database" "testing" "time" @@ -18,7 +18,7 @@ import ( const ownerPubBuf64 = "3yPmdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sY=" func Test_handleChannel(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) keypair := GenerateKeyPair(t) @@ -36,7 +36,7 @@ func Test_handleChannel(t *testing.T) { // Test 1: failed to handled message because unknown channel type channel := "unknown" - msg := generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg := generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID).Return(false, nil) mockRepository.On("GetChannelType", channel).Return("", nil) @@ -51,7 +51,7 @@ func Test_handleChannel(t *testing.T) { // Test 2: failed to handled message because db is disconnected when querying the channel type channel = "disconnectedDB" - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID).Return(false, nil) mockRepository.On("GetChannelType", channel). @@ -66,7 +66,7 @@ func Test_handleChannel(t *testing.T) { // Test 3: failed to handled message because message already exists - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID).Return(true, nil) @@ -78,7 +78,7 @@ func Test_handleChannel(t *testing.T) { // Test 4: failed to handled message because db is disconnected when querying if the message already exists - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID). Return(false, xerrors.Errorf("DB is disconnected")) @@ -91,7 +91,7 @@ func Test_handleChannel(t *testing.T) { // Test 5: failed to handled message because the format of messageID - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) expectedMsgID := msg.MessageID msg.MessageID = base64.URLEncoding.EncodeToString([]byte("wrong messageID")) @@ -103,7 +103,7 @@ func Test_handleChannel(t *testing.T) { // Test 6: failed to handled message because wrong sender - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Sender = base64.URLEncoding.EncodeToString([]byte("wrong sender")) args = append(args, input{ @@ -114,7 +114,7 @@ func Test_handleChannel(t *testing.T) { // Test 7: failed to handled message because wrong data - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong data")) args = append(args, input{ @@ -125,7 +125,7 @@ func Test_handleChannel(t *testing.T) { // Test 8: failed to handled message because wrong signature - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong signature")) args = append(args, input{ @@ -136,7 +136,7 @@ func Test_handleChannel(t *testing.T) { // Test 9: failed to handled message because wrong signature encoding - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Signature = "wrong signature" args = append(args, input{ @@ -147,7 +147,7 @@ func Test_handleChannel(t *testing.T) { // Test 10: failed to handled message because wrong signature encoding - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Sender = "wrong sender" args = append(args, input{ @@ -158,7 +158,7 @@ func Test_handleChannel(t *testing.T) { // Test 11: failed to handled message because wrong signature encoding - msg = generatortest.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) msg.Data = "wrong data" args = append(args, input{ diff --git a/be1-go/internal/handler/chirp_test.go b/be1-go/internal/handler/chirp_test.go index b11887567f..dbba93c278 100644 --- a/be1-go/internal/handler/chirp_test.go +++ b/be1-go/internal/handler/chirp_test.go @@ -6,25 +6,22 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + mock2 "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "strings" "testing" "time" ) func Test_handleChannelChirp(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state2.SetState(subs, peers, queries, hubParams) @@ -40,7 +37,7 @@ func Test_handleChannelChirp(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) sender := "3yPmdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sY=" @@ -138,9 +135,9 @@ func Test_handleChannelChirp(t *testing.T) { } func newChirpAddMsg(t *testing.T, channelID string, sender string, timestamp int64, - mockRepository *repository.MockRepository, isError bool) message.Message { + mockRepository *mock2.Repository, isError bool) message.Message { - msg := generatortest.NewChirpAddMsg(t, sender, nil, timestamp) + msg := generator.NewChirpAddMsg(t, sender, nil, timestamp) errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) @@ -161,9 +158,9 @@ func newChirpAddMsg(t *testing.T, channelID string, sender string, timestamp int } func newChirpDeleteMsg(t *testing.T, channelID string, sender string, chirpID string, - timestamp int64, mockRepository *repository.MockRepository, isError bool) message.Message { + timestamp int64, mockRepository *mock2.Repository, isError bool) message.Message { - msg := generatortest.NewChirpDeleteMsg(t, sender, nil, chirpID, timestamp) + msg := generator.NewChirpDeleteMsg(t, sender, nil, chirpID, timestamp) errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) diff --git a/be1-go/internal/handler/coin_test.go b/be1-go/internal/handler/coin_test.go index a3b1bb22bd..27bf8c65e1 100644 --- a/be1-go/internal/handler/coin_test.go +++ b/be1-go/internal/handler/coin_test.go @@ -9,14 +9,10 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/network/socket" - "popstellar/internal/repository" + "popstellar/internal/mocks" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "testing" ) @@ -27,18 +23,18 @@ type inputTestHandleChannelCoin struct { channelID string message message.Message hasError bool - sockets []*socket.FakeSocket + sockets []*mocks.FakeSocket } func Test_handleChannelCoin(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state2.SetState(subs, peers, queries, hubParams) - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) inputs := make([]inputTestHandleChannelCoin, 0) @@ -120,7 +116,7 @@ func Test_handleChannelCoin(t *testing.T) { } -func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository *repository.MockRepository) inputTestHandleChannelCoin { +func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository *mocks.Repository) inputTestHandleChannelCoin { laoID := messagedata.Hash(name) var sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" var channelID = "/root/" + laoID + "/coin" @@ -141,7 +137,7 @@ func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository.On("StoreMessageAndData", channelID, m).Return(nil) - sockets := []*socket.FakeSocket{ + sockets := []*mocks.FakeSocket{ {Id: laoID + "0"}, {Id: laoID + "1"}, {Id: laoID + "2"}, diff --git a/be1-go/internal/handler/election.go b/be1-go/internal/handler/election.go index 9f48937a41..6dc0a8dc14 100644 --- a/be1-go/internal/handler/election.go +++ b/be1-go/internal/handler/election.go @@ -12,7 +12,7 @@ import ( "popstellar/internal/message/query/method/message" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" - "popstellar/internal/types/election" + "popstellar/internal/types" "sort" ) @@ -391,7 +391,7 @@ func verifyVote(vote messagedata.Vote, channelPath, electionID string) *answer.E return nil } -func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[string]election.Question) *answer.Error { +func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[string]types.Question) *answer.Error { var voteIDs []string for _, question := range questions { for _, validVote := range question.ValidVotes { @@ -413,7 +413,7 @@ func verifyRegisteredVotes(electionEnd messagedata.ElectionEnd, questions map[st return nil } -func createElectionResult(questions map[string]election.Question, channelPath string) (message.Message, *answer.Error) { +func createElectionResult(questions map[string]types.Question, channelPath string) (message.Message, *answer.Error) { resultElection, errAnswer := computeElectionResult(questions, channelPath) if errAnswer != nil { return message.Message{}, errAnswer.Wrap("createElectionResult") @@ -453,7 +453,7 @@ func createElectionResult(questions map[string]election.Question, channelPath st return electionResultMsg, nil } -func computeElectionResult(questions map[string]election.Question, channelPath string) ( +func computeElectionResult(questions map[string]types.Question, channelPath string) ( messagedata.ElectionResult, *answer.Error) { db, errAnswer := database.GetElectionRepositoryInstance() if errAnswer != nil { @@ -503,7 +503,7 @@ func computeElectionResult(questions map[string]election.Question, channelPath s return resultElection, nil } -func getVoteIndex(vote election.ValidVote, electionType, channelPath string) (int, bool) { +func getVoteIndex(vote types.ValidVote, electionType, channelPath string) (int, bool) { switch electionType { case messagedata.OpenBallot: index, _ := vote.Index.(int) diff --git a/be1-go/internal/handler/election_test.go b/be1-go/internal/handler/election_test.go index c5bebfcd11..b3a7edcc8a 100644 --- a/be1-go/internal/handler/election_test.go +++ b/be1-go/internal/handler/election_test.go @@ -9,29 +9,25 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + mock2 "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/types/election" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "testing" ) func Test_handleChannelElection(t *testing.T) { var args []input - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() ownerPubBuf, err := base64.URLEncoding.DecodeString(ownerPubBuf64) require.NoError(t, err) @@ -221,7 +217,7 @@ func Test_handleChannelElection(t *testing.T) { contains: "", }) - votes := []generatortest.VoteInt{ + votes := []generator.VoteInt{ { ID: base64.URLEncoding.EncodeToString([]byte("voteID1")), Question: base64.URLEncoding.EncodeToString([]byte("questionID1")), @@ -282,7 +278,7 @@ func Test_handleChannelElection(t *testing.T) { channelPath = "/root/" + laoID + "/" + electionID //Test 18 Error when VoteCastVote question is not present in election setup - questions := map[string]election.Question{ + questions := map[string]types.Question{ base64.URLEncoding.EncodeToString([]byte("questionID2")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID2")))}, base64.URLEncoding.EncodeToString([]byte("questionID3")): {ID: []byte(base64.URLEncoding.EncodeToString([]byte("questionID3")))}, } @@ -301,7 +297,7 @@ func Test_handleChannelElection(t *testing.T) { channelPath = "/root/" + laoID + "/" + electionID //Test 19 Error when VoteCastVote contains a string vote in an OpenBallot election - stringVotes := []generatortest.VoteString{ + stringVotes := []generator.VoteString{ { ID: base64.URLEncoding.EncodeToString([]byte("voteID1")), Question: base64.URLEncoding.EncodeToString([]byte("questionID2")), @@ -323,7 +319,7 @@ func Test_handleChannelElection(t *testing.T) { channelPath = "/root/" + laoID + "/" + electionID //Test 20 Error when VoteCastVote contains a int vote in an SecretBallot election - intVotes := []generatortest.VoteInt{ + intVotes := []generator.VoteInt{ { ID: base64.URLEncoding.EncodeToString([]byte("voteID1")), Question: base64.URLEncoding.EncodeToString([]byte("questionID2")), @@ -363,7 +359,7 @@ func Test_handleChannelElection(t *testing.T) { questionID := base64.URLEncoding.EncodeToString([]byte("questionID2")) voteID := messagedata.Hash(voteFlag, electionID, questionID, "1") - votes = []generatortest.VoteInt{ + votes = []generator.VoteInt{ { ID: voteID, Question: questionID, @@ -410,9 +406,9 @@ func Test_handleChannelElection(t *testing.T) { } func newElectionOpenMsg(t *testing.T, owner kyber.Point, sender, laoID, electionID, channelPath, state string, - createdAt int64, isError bool, mockRepository *repository.MockRepository) message.Message { + createdAt int64, isError bool, mockRepository *mock2.Repository) message.Message { - msg := generatortest.NewElectionOpenMsg(t, sender, laoID, electionID, 1, nil) + msg := generator.NewElectionOpenMsg(t, sender, laoID, electionID, 1, nil) mockRepository.On("GetLAOOrganizerPubKey", channelPath).Return(owner, nil) @@ -433,9 +429,9 @@ func newElectionOpenMsg(t *testing.T, owner kyber.Point, sender, laoID, election } func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionID, channelPath, state, votes string, - createdAt int64, isError bool, mockRepository *repository.MockRepository) message.Message { + createdAt int64, isError bool, mockRepository *mock2.Repository) message.Message { - msg := generatortest.NewElectionCloseMsg(t, sender, laoID, electionID, votes, 1, nil) + msg := generator.NewElectionCloseMsg(t, sender, laoID, electionID, votes, 1, nil) mockRepository.On("GetLAOOrganizerPubKey", channelPath).Return(owner, nil) @@ -449,10 +445,10 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } if votes != "" { - questions := map[string]election.Question{ + questions := map[string]types.Question{ "questionID1": { ID: []byte("questionID1"), - ValidVotes: map[string]election.ValidVote{ + ValidVotes: map[string]types.ValidVote{ "voteID1": { ID: "voteID1", }, @@ -463,7 +459,7 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI }, "questionID2": { ID: []byte("questionID2"), - ValidVotes: map[string]election.ValidVote{ + ValidVotes: map[string]types.ValidVote{ "voteID3": { ID: "voteID3", }, @@ -484,10 +480,10 @@ func newElectionEndMsg(t *testing.T, owner kyber.Point, sender, laoID, electionI } func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath, state, electionType string, - createdAt int64, votes []generatortest.VoteInt, questions map[string]election.Question, owner kyber.Point, - mockRepository *repository.MockRepository, isEroor bool) message.Message { + createdAt int64, votes []generator.VoteInt, questions map[string]types.Question, owner kyber.Point, + mockRepository *mock2.Repository, isEroor bool) message.Message { - msg := generatortest.NewVoteCastVoteIntMsg(t, sender, laoID, electionID, 1, votes, nil) + msg := generator.NewVoteCastVoteIntMsg(t, sender, laoID, electionID, 1, votes, nil) mockRepository.On("GetLAOOrganizerPubKey", electionPath).Return(owner, nil) mockRepository.On("GetElectionAttendees", electionPath).Return(map[string]struct{}{ownerPubBuf64: {}}, nil) @@ -522,10 +518,10 @@ func newVoteCastVoteIntMsg(t *testing.T, sender, laoID, electionID, electionPath } func newVoteCastVoteStringMsg(t *testing.T, sender, laoID, electionID, electionPath, electionType string, - createdAt int64, votes []generatortest.VoteString, questions map[string]election.Question, owner kyber.Point, - mockRepository *repository.MockRepository) message.Message { + createdAt int64, votes []generator.VoteString, questions map[string]types.Question, owner kyber.Point, + mockRepository *mock2.Repository) message.Message { - msg := generatortest.NewVoteCastVoteStringMsg(t, sender, laoID, electionID, 1, votes, nil) + msg := generator.NewVoteCastVoteStringMsg(t, sender, laoID, electionID, 1, votes, nil) mockRepository.On("GetLAOOrganizerPubKey", electionPath).Return(owner, nil) mockRepository.On("GetElectionAttendees", electionPath).Return(map[string]struct{}{ownerPubBuf64: {}}, nil) diff --git a/be1-go/internal/handler/federation_test.go b/be1-go/internal/handler/federation_test.go index eb0d100f43..067ab463c4 100644 --- a/be1-go/internal/handler/federation_test.go +++ b/be1-go/internal/handler/federation_test.go @@ -13,16 +13,12 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query" "popstellar/internal/message/query/method" - "popstellar/internal/mock/generatortest" - "popstellar/internal/network/socket" - "popstellar/internal/repository" + mock2 "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "testing" "time" ) @@ -30,13 +26,13 @@ import ( func Test_handleChannelFederation(t *testing.T) { var args []input - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -74,7 +70,7 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 1", channel: channelPath, - msg: generatortest.NewFederationChallengeRequest(t, + msg: generator.NewFederationChallengeRequest(t, notOrganizer, validUntil, notOrganizerSk), isError: true, contains: "sender is not the organizer of the channel", @@ -84,7 +80,7 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 2", channel: channelPath, - msg: generatortest.NewFederationChallengeRequest(t, + msg: generator.NewFederationChallengeRequest(t, organizer, -1, organizerSk), isError: true, contains: "VerifyJSON", @@ -95,9 +91,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 3", channel: channelPath, - msg: generatortest.NewFederationExpect(t, notOrganizer, laoID, + msg: generator.NewFederationExpect(t, notOrganizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), notOrganizerSk), isError: true, @@ -108,9 +104,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 4", channel: channelPath, - msg: generatortest.NewFederationExpect(t, organizer, laoID, + msg: generator.NewFederationExpect(t, organizer, laoID, "ws:localhost:12345/client", organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -121,9 +117,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 5", channel: channelPath, - msg: generatortest.NewFederationExpect(t, organizer, laoID, + msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, "organizer2", - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -134,9 +130,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 6", channel: channelPath, - msg: generatortest.NewFederationExpect(t, organizer, "laoID", + msg: generator.NewFederationExpect(t, organizer, "laoID", serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -147,9 +143,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 7", channel: channelPath, - msg: generatortest.NewFederationExpect(t, organizer, laoID, + msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallengeRequest(t, organizer, + generator.NewFederationChallengeRequest(t, organizer, validUntil, organizerSk), organizerSk), isError: true, @@ -160,9 +156,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 8", channel: channelPath, - msg: generatortest.NewFederationExpect(t, organizer, laoID, + msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, notOrganizer, + generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), organizerSk), isError: true, @@ -174,9 +170,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 9", channel: channelPath, - msg: generatortest.NewFederationInit(t, notOrganizer, laoID, + msg: generator.NewFederationInit(t, notOrganizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), notOrganizerSk), isError: true, @@ -187,9 +183,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 10", channel: channelPath, - msg: generatortest.NewFederationInit(t, organizer, laoID, + msg: generator.NewFederationInit(t, organizer, laoID, "ws:localhost:12345/client", organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -200,9 +196,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 11", channel: channelPath, - msg: generatortest.NewFederationInit(t, organizer, laoID, + msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, "organizer2", - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -213,9 +209,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 12", channel: channelPath, - msg: generatortest.NewFederationInit(t, organizer, "laoID", + msg: generator.NewFederationInit(t, organizer, "laoID", serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, organizer, + generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk), isError: true, @@ -226,9 +222,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 13", channel: channelPath, - msg: generatortest.NewFederationInit(t, organizer, laoID, + msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallengeRequest(t, organizer, + generator.NewFederationChallengeRequest(t, organizer, validUntil, organizerSk), organizerSk), isError: true, @@ -239,9 +235,9 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 14", channel: channelPath, - msg: generatortest.NewFederationInit(t, organizer, laoID, + msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, organizer2, - generatortest.NewFederationChallenge(t, notOrganizer, + generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), organizerSk), isError: true, @@ -264,7 +260,7 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 15", channel: channelPath, - msg: generatortest.NewFederationChallenge(t, notOrganizer, value, + msg: generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), isError: true, contains: "failed to get federation expect", @@ -274,8 +270,8 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 16", channel: channelPath, - msg: generatortest.NewSuccessFederationResult(t, organizer2, - organizer, generatortest.NewFederationChallengeRequest(t, + msg: generator.NewSuccessFederationResult(t, organizer2, + organizer, generator.NewFederationChallengeRequest(t, organizer2, validUntil, organizer2Sk), organizer2Sk), isError: true, contains: "invalid message field", @@ -285,8 +281,8 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 17", channel: channelPath, - msg: generatortest.NewSuccessFederationResult(t, organizer2, - notOrganizer, generatortest.NewFederationChallenge(t, organizer2, + msg: generator.NewSuccessFederationResult(t, organizer2, + notOrganizer, generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk), organizer2Sk), isError: true, contains: "invalid message field", @@ -301,8 +297,8 @@ func Test_handleChannelFederation(t *testing.T) { args = append(args, input{ name: "Test 18", channel: channelPath, - msg: generatortest.NewSuccessFederationResult(t, organizer2, - organizer, generatortest.NewFederationChallenge(t, organizer2, + msg: generator.NewSuccessFederationResult(t, organizer2, + organizer, generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk), organizer2Sk), isError: true, contains: "failed to get federation init", @@ -321,13 +317,13 @@ func Test_handleChannelFederation(t *testing.T) { } func Test_handleRequestChallenge(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -347,7 +343,7 @@ func Test_handleRequestChallenge(t *testing.T) { errAnswer := subs.AddChannel(channelPath) require.Nil(t, errAnswer) - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mock2.FakeSocket{Id: "1"} errAnswer = subs.Subscribe(channelPath, &fakeSocket) require.Nil(t, errAnswer) @@ -356,7 +352,7 @@ func Test_handleRequestChallenge(t *testing.T) { mockRepository.On("StoreMessageAndData", channelPath, mock.AnythingOfType("message.Message")).Return(nil) - errAnswer = handleRequestChallenge(generatortest.NewFederationChallengeRequest(t, organizer, time.Now().Unix(), + errAnswer = handleRequestChallenge(generator.NewFederationChallengeRequest(t, organizer, time.Now().Unix(), organizerSk), channelPath) require.Nil(t, errAnswer) @@ -377,13 +373,13 @@ func Test_handleRequestChallenge(t *testing.T) { } func Test_handleFederationExpect(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -428,8 +424,8 @@ func Test_handleFederationExpect(t *testing.T) { mockRepository.On("IsChallengeValid", server, federationChallenge, channelPath).Return(nil) - federationExpect := generatortest.NewFederationExpect(t, organizer, laoID, - serverAddressA, organizer2, generatortest.NewFederationChallenge(t, + federationExpect := generator.NewFederationExpect(t, organizer, laoID, + serverAddressA, organizer2, generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), organizerSk) errAnswer := handleExpect(federationExpect, channelPath) @@ -437,13 +433,13 @@ func Test_handleFederationExpect(t *testing.T) { } func Test_handleFederationInit(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -471,10 +467,10 @@ func Test_handleFederationInit(t *testing.T) { value := "82eadde2a4ba832518b90bb93c8480ee1ae16a91d5efe9281e91e2ec11da03e4" validUntil := time.Now().Add(5 * time.Minute).Unix() - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk) - initMsg := generatortest.NewFederationInit(t, organizer, laoID2, + initMsg := generator.NewFederationInit(t, organizer, laoID2, serverAddressA, organizer2, challengeMsg, organizerSk) mockRepository.On("GetOrganizerPubKey", laoPath).Return(organizerPk, nil) @@ -520,13 +516,13 @@ func Test_handleFederationInit(t *testing.T) { } func Test_handleFederationChallenge(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -555,11 +551,11 @@ func Test_handleFederationChallenge(t *testing.T) { errAnswer = subs.AddChannel(channelPath2) require.Nil(t, errAnswer) - fakeSocket1 := socket.FakeSocket{Id: "1"} + fakeSocket1 := mock2.FakeSocket{Id: "1"} errAnswer = subs.Subscribe(channelPath, &fakeSocket1) require.Nil(t, errAnswer) - fakeSocket2 := socket.FakeSocket{Id: "2"} + fakeSocket2 := mock2.FakeSocket{Id: "2"} errAnswer = subs.Subscribe(channelPath2, &fakeSocket2) require.Nil(t, errAnswer) @@ -573,10 +569,10 @@ func Test_handleFederationChallenge(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk) - challengeMsg2 := generatortest.NewFederationChallenge(t, organizer2, + challengeMsg2 := generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk) federationExpect := messagedata.FederationExpect{ @@ -627,13 +623,13 @@ func Test_handleFederationChallenge(t *testing.T) { } func Test_handleFederationResult(t *testing.T) { - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() organizerPk, organizerSk := generateKeys() organizer2Pk, organizer2Sk := generateKeys() @@ -658,7 +654,7 @@ func Test_handleFederationResult(t *testing.T) { errAnswer := subs.AddChannel(channelPath) require.Nil(t, errAnswer) - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mock2.FakeSocket{Id: "1"} errAnswer = subs.Subscribe(channelPath, &fakeSocket) require.Nil(t, errAnswer) @@ -672,10 +668,10 @@ func Test_handleFederationResult(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk) - challengeMsg2 := generatortest.NewFederationChallenge(t, organizer2, value, + challengeMsg2 := generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk) federationInit := messagedata.FederationInit{ @@ -687,7 +683,7 @@ func Test_handleFederationResult(t *testing.T) { ChallengeMsg: challengeMsg, } - federationResultMsg := generatortest.NewSuccessFederationResult(t, + federationResultMsg := generator.NewSuccessFederationResult(t, organizer2, organizer, challengeMsg2, organizer2Sk) mockRepository.On("GetOrganizerPubKey", laoPath).Return(organizerPk, nil) diff --git a/be1-go/internal/handler/incoming_message_test.go b/be1-go/internal/handler/incoming_message_test.go index 25f30f65e6..99f4620011 100644 --- a/be1-go/internal/handler/incoming_message_test.go +++ b/be1-go/internal/handler/incoming_message_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" "io" "os" - "popstellar/internal/mock/generatortest" - "popstellar/internal/network/socket" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/utils" "popstellar/internal/validation" "testing" @@ -43,18 +43,18 @@ func Test_handleIncomingMessage(t *testing.T) { args = append(args, input{ name: "Test 1", - message: generatortest.NewNothingQuery(t, 999), + message: generator.NewNothingQuery(t, 999), contains: "invalid json", }) // Test 2: failed to handled popanswer because wrong publish popanswer format - msg := generatortest.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) + msg := generator.NewNothingMsg(t, base64.URLEncoding.EncodeToString([]byte("sender")), nil) msg.MessageID = "wrong messageID" args = append(args, input{ name: "Test 2", - message: generatortest.NewPublishQuery(t, 1, "/root/lao1", msg), + message: generator.NewPublishQuery(t, 1, "/root/lao1", msg), contains: "invalid json", }) @@ -62,7 +62,7 @@ func Test_handleIncomingMessage(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} err := HandleIncomingMessage(&fakeSocket, arg.message) require.Error(t, err) require.Contains(t, err.Error(), arg.contains) diff --git a/be1-go/internal/handler/lao_test.go b/be1-go/internal/handler/lao_test.go index 4cb40d5bd0..bdfec2a09c 100644 --- a/be1-go/internal/handler/lao_test.go +++ b/be1-go/internal/handler/lao_test.go @@ -8,15 +8,12 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + mock2 "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "strconv" "strings" "testing" @@ -24,10 +21,10 @@ import ( ) func Test_handleChannelLao(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -44,7 +41,7 @@ func Test_handleChannelLao(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") var args []input - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) laoID := base64.URLEncoding.EncodeToString([]byte("laoID")) @@ -269,13 +266,13 @@ func Test_handleChannelLao(t *testing.T) { } } -func newLaoStateMsg(t *testing.T, organizer, laoID string, mockRepository *repository.MockRepository) message.Message { +func newLaoStateMsg(t *testing.T, organizer, laoID string, mockRepository *mock2.Repository) message.Message { modificationID := base64.URLEncoding.EncodeToString([]byte("modificationID")) name := "laoName" creation := time.Now().Unix() lastModified := time.Now().Unix() - msg := generatortest.NewLaoStateMsg(t, organizer, laoID, name, modificationID, creation, lastModified, nil) + msg := generator.NewLaoStateMsg(t, organizer, laoID, name, modificationID, creation, lastModified, nil) mockRepository.On("HasMessage", modificationID). Return(true, nil) @@ -288,7 +285,7 @@ func newLaoStateMsg(t *testing.T, organizer, laoID string, mockRepository *repos } func newRollCallCreateMsg(t *testing.T, sender, laoID, laoName string, creation, start, end int64, isError bool, - mockRepository *repository.MockRepository) message.Message { + mockRepository *mock2.Repository) message.Message { createID := messagedata.Hash( messagedata.RollCallFlag, @@ -297,7 +294,7 @@ func newRollCallCreateMsg(t *testing.T, sender, laoID, laoName string, creation, goodLaoName, ) - msg := generatortest.NewRollCallCreateMsg(t, sender, laoName, createID, creation, start, end, nil) + msg := generator.NewRollCallCreateMsg(t, sender, laoName, createID, creation, start, end, nil) if !isError { mockRepository.On("StoreMessageAndData", laoID, msg).Return(nil) @@ -307,7 +304,7 @@ func newRollCallCreateMsg(t *testing.T, sender, laoID, laoName string, creation, } func newRollCallOpenMsg(t *testing.T, sender, laoID, opens, prevID string, openedAt int64, isError bool, - mockRepository *repository.MockRepository) message.Message { + mockRepository *mock2.Repository) message.Message { openID := messagedata.Hash( messagedata.RollCallFlag, @@ -316,7 +313,7 @@ func newRollCallOpenMsg(t *testing.T, sender, laoID, opens, prevID string, opene strconv.Itoa(int(openedAt)), ) - msg := generatortest.NewRollCallOpenMsg(t, sender, openID, opens, openedAt, nil) + msg := generator.NewRollCallOpenMsg(t, sender, openID, opens, openedAt, nil) if !isError { mockRepository.On("StoreMessageAndData", laoID, msg).Return(nil) @@ -329,7 +326,7 @@ func newRollCallOpenMsg(t *testing.T, sender, laoID, opens, prevID string, opene } func newRollCallCloseMsg(t *testing.T, sender, laoID, closes, prevID string, closedAt int64, isError bool, - mockRepository *repository.MockRepository) message.Message { + mockRepository *mock2.Repository) message.Message { closeID := messagedata.Hash( messagedata.RollCallFlag, @@ -340,7 +337,7 @@ func newRollCallCloseMsg(t *testing.T, sender, laoID, closes, prevID string, clo attendees := []string{base64.URLEncoding.EncodeToString([]byte("a")), base64.URLEncoding.EncodeToString([]byte("b"))} - msg := generatortest.NewRollCallCloseMsg(t, sender, closeID, closes, closedAt, attendees, nil) + msg := generator.NewRollCallCloseMsg(t, sender, closeID, closes, closedAt, attendees, nil) if !isError { var channels []string @@ -359,7 +356,7 @@ func newRollCallCloseMsg(t *testing.T, sender, laoID, closes, prevID string, clo func newElectionSetupMsg(t *testing.T, organizer kyber.Point, sender, setupLao, laoID, electionName, question, version string, createdAt, start, end int64, - isError bool, mockRepository *repository.MockRepository) message.Message { + isError bool, mockRepository *mock2.Repository) message.Message { electionSetupID := messagedata.Hash( messagedata.ElectionFlag, @@ -389,7 +386,7 @@ func newElectionSetupMsg(t *testing.T, organizer kyber.Point, sender, }) } - msg := generatortest.NewElectionSetupMsg(t, sender, electionSetupID, setupLao, electionName, version, createdAt, start, + msg := generator.NewElectionSetupMsg(t, sender, electionSetupID, setupLao, electionName, version, createdAt, start, end, questions, nil) mockRepository.On("GetOrganizerPubKey", laoID).Return(organizer, nil) diff --git a/be1-go/internal/handler/query_test.go b/be1-go/internal/handler/query_test.go index 4f3c8122fd..c8c2c88b10 100644 --- a/be1-go/internal/handler/query_test.go +++ b/be1-go/internal/handler/query_test.go @@ -7,16 +7,12 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/network/socket" - "popstellar/internal/repository" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "testing" ) @@ -31,7 +27,7 @@ func Test_handleQuery(t *testing.T) { // Test 1: failed to handled popquery because unknown method - msg := generatortest.NewNothingQuery(t, 999) + msg := generator.NewNothingQuery(t, 999) args = append(args, input{ name: "Test 1", @@ -43,7 +39,7 @@ func Test_handleQuery(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - fakeSocket := socket.FakeSocket{Id: "fakesocket"} + fakeSocket := mocks.FakeSocket{Id: "fakesocket"} errAnswer := handleQuery(&fakeSocket, arg.message) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) @@ -52,10 +48,10 @@ func Test_handleQuery(t *testing.T) { } func Test_handleGreetServer(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -66,7 +62,7 @@ func Test_handleGreetServer(t *testing.T) { type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket message []byte needGreet bool isError bool @@ -75,11 +71,11 @@ func Test_handleGreetServer(t *testing.T) { args := make([]input, 0) - greetServer := generatortest.NewGreetServerQuery(t, "pk", "client", "server") + greetServer := generator.NewGreetServerQuery(t, "pk", "client", "server") // Test 1: reply with greet server when receiving a greet server from a new server - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} args = append(args, input{ name: "Test 1", @@ -91,7 +87,7 @@ func Test_handleGreetServer(t *testing.T) { // Test 2: doesn't reply with greet server when already greeted the server - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} peers.AddPeerGreeted(fakeSocket.Id) @@ -105,7 +101,7 @@ func Test_handleGreetServer(t *testing.T) { // Test 3: return an error if the socket ID is already used by another server - fakeSocket = socket.FakeSocket{Id: "3"} + fakeSocket = mocks.FakeSocket{Id: "3"} err := peers.AddPeerInfo(fakeSocket.Id, method.GreetServerParams{}) require.NoError(t, err) @@ -139,16 +135,16 @@ func Test_handleGreetServer(t *testing.T) { } func Test_handleSubscribe(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket ID int channel string message []byte @@ -160,7 +156,7 @@ func Test_handleSubscribe(t *testing.T) { // Test 1: successfully subscribe to a channel - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" @@ -172,13 +168,13 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generator.NewSubscribeQuery(t, ID, channel), isError: false, }) // Test 2: failed to subscribe to an unknown channel - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" @@ -187,14 +183,14 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generator.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to unknown channel", }) // cannot Subscribe to root - fakeSocket = socket.FakeSocket{Id: "3"} + fakeSocket = mocks.FakeSocket{Id: "3"} ID = 3 channel = "/root" @@ -203,7 +199,7 @@ func Test_handleSubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewSubscribeQuery(t, ID, channel), + message: generator.NewSubscribeQuery(t, ID, channel), isError: true, contains: "cannot Subscribe to root channel", }) @@ -228,16 +224,16 @@ func Test_handleSubscribe(t *testing.T) { } func Test_handleUnsubscribe(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket ID int channel string message []byte @@ -249,7 +245,7 @@ func Test_handleUnsubscribe(t *testing.T) { // Test 1: successfully unsubscribe from a subscribed channel - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" @@ -264,13 +260,13 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generator.NewUnsubscribeQuery(t, ID, channel), isError: false, }) // Test 2: failed to unsubscribe because not subscribed to channel - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" @@ -282,14 +278,14 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generator.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from a channel not subscribed", }) // Test 3: failed to unsubscribe because unknown channel - fakeSocket = socket.FakeSocket{Id: "3"} + fakeSocket = mocks.FakeSocket{Id: "3"} ID = 3 channel = "/root/lao3" @@ -298,14 +294,14 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generator.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from unknown channel", }) // Test 3: failed to unsubscribe because cannot unsubscribe from root channel - fakeSocket = socket.FakeSocket{Id: "4"} + fakeSocket = mocks.FakeSocket{Id: "4"} ID = 4 channel = "/root" @@ -314,7 +310,7 @@ func Test_handleUnsubscribe(t *testing.T) { socket: fakeSocket, ID: ID, channel: channel, - message: generatortest.NewUnsubscribeQuery(t, ID, channel), + message: generator.NewUnsubscribeQuery(t, ID, channel), isError: true, contains: "cannot Unsubscribe from root channel", }) @@ -340,19 +336,19 @@ func Test_handleUnsubscribe(t *testing.T) { } func Test_handleCatchUp(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket ID int message []byte expected []message.Message @@ -364,14 +360,14 @@ func Test_handleCatchUp(t *testing.T) { // Test 1: successfully catchup 4 messages on a channel - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" messagesToCatchUp := []message.Message{ - generatortest.NewNothingMsg(t, "sender1", nil), - generatortest.NewNothingMsg(t, "sender2", nil), - generatortest.NewNothingMsg(t, "sender3", nil), - generatortest.NewNothingMsg(t, "sender4", nil), + generator.NewNothingMsg(t, "sender1", nil), + generator.NewNothingMsg(t, "sender2", nil), + generator.NewNothingMsg(t, "sender3", nil), + generator.NewNothingMsg(t, "sender4", nil), } mockRepository.On("GetAllMessagesFromChannel", channel).Return(messagesToCatchUp, nil) @@ -380,14 +376,14 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest.NewCatchupQuery(t, ID, channel), + message: generator.NewCatchupQuery(t, ID, channel), expected: messagesToCatchUp, isError: false, }) // Test 2: failed to catchup because DB is disconnected - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" @@ -398,7 +394,7 @@ func Test_handleCatchUp(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest.NewCatchupQuery(t, ID, channel), + message: generator.NewCatchupQuery(t, ID, channel), isError: true, contains: "DB is disconnected", }) @@ -422,19 +418,19 @@ func Test_handleCatchUp(t *testing.T) { } func Test_handleHeartbeat(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket message []byte expected map[string][]string isError bool @@ -447,7 +443,7 @@ func Test_handleHeartbeat(t *testing.T) { // Test 1: successfully handled heartbeat with some messages to catching up - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} heartbeatMsgIDs1 := make(map[string][]string) heartbeatMsgIDs1["/root"] = []string{ @@ -478,14 +474,14 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 1", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs1), + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs1), expected: expected1, isError: false, }) // Test 2: successfully handled heartbeat with nothing to catching up - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} heartbeatMsgIDs2 := make(map[string][]string) heartbeatMsgIDs2["/root"] = []string{ @@ -499,13 +495,13 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "Test 2", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs2), + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs2), isError: false, }) // Test 3: failed to handled heartbeat because DB is disconnected - fakeSocket = socket.FakeSocket{Id: "3"} + fakeSocket = mocks.FakeSocket{Id: "3"} heartbeatMsgIDs3 := make(map[string][]string) heartbeatMsgIDs3["/root"] = []string{ @@ -524,7 +520,7 @@ func Test_handleHeartbeat(t *testing.T) { args = append(args, input{ name: "failed to popquery DB", socket: fakeSocket, - message: generatortest.NewHeartbeatQuery(t, heartbeatMsgIDs3), + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs3), isError: true, contains: "DB is disconnected", }) @@ -554,19 +550,19 @@ func Test_handleHeartbeat(t *testing.T) { } func Test_handleGetMessagesByID(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket socket.FakeSocket + socket mocks.FakeSocket ID int message []byte expected map[string][]message.Message @@ -578,19 +574,19 @@ func Test_handleGetMessagesByID(t *testing.T) { // Test 1: successfully handled getMessagesByID and sent the result - fakeSocket := socket.FakeSocket{Id: "1"} + fakeSocket := mocks.FakeSocket{Id: "1"} ID := 1 expected1 := make(map[string][]message.Message) expected1["/root"] = []message.Message{ - generatortest.NewNothingMsg(t, "sender1", nil), - generatortest.NewNothingMsg(t, "sender2", nil), - generatortest.NewNothingMsg(t, "sender3", nil), - generatortest.NewNothingMsg(t, "sender4", nil), + generator.NewNothingMsg(t, "sender1", nil), + generator.NewNothingMsg(t, "sender2", nil), + generator.NewNothingMsg(t, "sender3", nil), + generator.NewNothingMsg(t, "sender4", nil), } expected1["/root/lao1"] = []message.Message{ - generatortest.NewNothingMsg(t, "sender5", nil), - generatortest.NewNothingMsg(t, "sender6", nil), + generator.NewNothingMsg(t, "sender5", nil), + generator.NewNothingMsg(t, "sender6", nil), } paramsGetMessagesByID1 := make(map[string][]string) @@ -607,14 +603,14 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 1", socket: fakeSocket, ID: ID, - message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), + message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), expected: expected1, isError: false, }) // Test 2: failed to handled getMessagesByID because DB is disconnected - fakeSocket = socket.FakeSocket{Id: "2"} + fakeSocket = mocks.FakeSocket{Id: "2"} ID = 2 paramsGetMessagesByID2 := make(map[string][]string) @@ -626,7 +622,7 @@ func Test_handleGetMessagesByID(t *testing.T) { name: "Test 2", socket: fakeSocket, ID: ID, - message: generatortest.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), + message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), isError: true, contains: "DB is disconnected", }) diff --git a/be1-go/internal/handler/reaction_test.go b/be1-go/internal/handler/reaction_test.go index 5c784d1e0d..f0b1d2b402 100644 --- a/be1-go/internal/handler/reaction_test.go +++ b/be1-go/internal/handler/reaction_test.go @@ -5,25 +5,22 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "strings" "testing" "time" ) func Test_handleChannelReaction(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state2.SetState(subs, peers, queries, hubParams) @@ -39,7 +36,7 @@ func Test_handleChannelReaction(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") - mockRepository := repository.NewMockRepository(t) + mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) sender := "3yPmdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sY=" @@ -225,9 +222,9 @@ func Test_handleChannelReaction(t *testing.T) { } func newReactionAddMsg(t *testing.T, channelID string, sender string, reactionCodePoint, chirpID string, timestamp int64, - mockRepository *repository.MockRepository, hasInvalidField, isNotAttendee bool) message.Message { + mockRepository *mocks.Repository, hasInvalidField, isNotAttendee bool) message.Message { - msg := generatortest.NewReactionAddMsg(t, sender, nil, reactionCodePoint, chirpID, timestamp) + msg := generator.NewReactionAddMsg(t, sender, nil, reactionCodePoint, chirpID, timestamp) errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) @@ -247,9 +244,9 @@ func newReactionAddMsg(t *testing.T, channelID string, sender string, reactionCo } func newReactionDeleteMsg(t *testing.T, channelID string, sender string, reactionID string, timestamp int64, - mockRepository *repository.MockRepository, hasInvalidField, hasNotReaction, isNotOwner, isNotAttendee bool) message.Message { + mockRepository *mocks.Repository, hasInvalidField, hasNotReaction, isNotOwner, isNotAttendee bool) message.Message { - msg := generatortest.NewReactionDeleteMsg(t, sender, nil, reactionID, timestamp) + msg := generator.NewReactionDeleteMsg(t, sender, nil, reactionID, timestamp) errAnswer := state2.AddChannel(channelID) require.Nil(t, errAnswer) diff --git a/be1-go/internal/handler/root_test.go b/be1-go/internal/handler/root_test.go index 0299cf3d5d..1d269a3ff1 100644 --- a/be1-go/internal/handler/root_test.go +++ b/be1-go/internal/handler/root_test.go @@ -8,16 +8,13 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/repository" + mock2 "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" "popstellar/internal/sqlite" - "popstellar/internal/types/hubparams" - peers2 "popstellar/internal/types/peers" - queries2 "popstellar/internal/types/queries" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "testing" "time" ) @@ -38,10 +35,10 @@ type input struct { } func Test_handleChannelRoot(t *testing.T) { - subs := types2.NewSubscribers() - queries := queries2.NewQueries(&noLog) - peers := peers2.NewPeers() - hubParams := hubparams.NewHubParams() + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() state.SetState(subs, peers, queries, hubParams) @@ -58,7 +55,7 @@ func Test_handleChannelRoot(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") var args []input - mockRepository := repository.NewMockRepository(t) + mockRepository := mock2.NewRepository(t) database.SetDatabase(mockRepository) ownerPubBuf, err := ownerPublicKey.MarshalBinary() @@ -92,7 +89,7 @@ func Test_handleChannelRoot(t *testing.T) { // Test 4: error when message data is not lao_create args = append(args, input{ name: "Test 4", - msg: generatortest.NewNothingMsg(t, owner, nil), + msg: generator.NewNothingMsg(t, owner, nil), isError: true, contains: "failed to validate schema", }) @@ -118,7 +115,7 @@ func Test_handleChannelRoot(t *testing.T) { } } -func newLaoCreateMsg(t *testing.T, organizer, sender, laoName string, mockRepository *repository.MockRepository, isError bool) message.Message { +func newLaoCreateMsg(t *testing.T, organizer, sender, laoName string, mockRepository *mock2.Repository, isError bool) message.Message { creation := time.Now().Unix() laoID := messagedata.Hash( organizer, @@ -126,7 +123,7 @@ func newLaoCreateMsg(t *testing.T, organizer, sender, laoName string, mockReposi goodLaoName, ) - msg := generatortest.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) + msg := generator.NewLaoCreateMsg(t, sender, laoID, laoName, creation, organizer, nil) mockRepository.On("HasChannel", RootPrefix+laoID).Return(false, nil) if !isError { diff --git a/be1-go/internal/message/messagedata/coin_post_transaction.go b/be1-go/internal/message/messagedata/coin_post_transaction.go index e1770cfc81..918d9814d3 100644 --- a/be1-go/internal/message/messagedata/coin_post_transaction.go +++ b/be1-go/internal/message/messagedata/coin_post_transaction.go @@ -7,7 +7,7 @@ import ( "golang.org/x/xerrors" "popstellar/internal/crypto" "popstellar/internal/message/answer" - "popstellar/internal/types/uint53" + "popstellar/internal/types" "strconv" ) @@ -36,8 +36,8 @@ type Input struct { // Output defines the destination for the money used in transaction type Output struct { - Value uint53.Uint53 `json:"value"` - Script LockScript `json:"script"` + Value types.Uint53 `json:"value"` + Script LockScript `json:"script"` } // LockScript defines the locking value for transaction @@ -55,11 +55,11 @@ type UnlockScript struct { // SumOutputs computes the sum of the amounts in all outputs. // It may signal an overflow error -func (transaction Transaction) SumOutputs() (uint53.Uint53, error) { - var acc uint53.Uint53 = 0 +func (transaction Transaction) SumOutputs() (types.Uint53, error) { + var acc types.Uint53 = 0 var err error for _, out := range transaction.Outputs { - acc, err = uint53.SafePlus(acc, out.Value) + acc, err = types.SafePlus(acc, out.Value) if err != nil { return 0, xerrors.Errorf("failed to perform uint53 addition: %v", err) } diff --git a/be1-go/internal/network/socket/fake_socket.go b/be1-go/internal/mocks/fake_socket.go similarity index 78% rename from be1-go/internal/network/socket/fake_socket.go rename to be1-go/internal/mocks/fake_socket.go index a363d442a0..c2bd0f2c51 100644 --- a/be1-go/internal/network/socket/fake_socket.go +++ b/be1-go/internal/mocks/fake_socket.go @@ -1,12 +1,15 @@ -package socket +package mocks -import "popstellar/internal/message/query/method/message" +import ( + "popstellar/internal/message/query/method/message" + "popstellar/internal/network/socket" +) // FakeSocket is a fake implementation of a Socket // // - implements socket.Socket type FakeSocket struct { - Socket + socket.Socket ResultID int Res []message.Message @@ -44,6 +47,6 @@ func (f *FakeSocket) GetMessage() []byte { return f.Msg } -func (f *FakeSocket) Type() SocketType { - return ClientSocketType +func (f *FakeSocket) Type() socket.SocketType { + return socket.ClientSocketType } diff --git a/be1-go/internal/mock/generatortest/chirp.go b/be1-go/internal/mocks/generator/chirp.go similarity index 97% rename from be1-go/internal/mock/generatortest/chirp.go rename to be1-go/internal/mocks/generator/chirp.go index c60efb1a67..3e330629d4 100644 --- a/be1-go/internal/mock/generatortest/chirp.go +++ b/be1-go/internal/mocks/generator/chirp.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/election.go b/be1-go/internal/mocks/generator/election.go similarity index 99% rename from be1-go/internal/mock/generatortest/election.go rename to be1-go/internal/mocks/generator/election.go index 509e0e02b0..5d912aa617 100644 --- a/be1-go/internal/mock/generatortest/election.go +++ b/be1-go/internal/mocks/generator/election.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/federation.go b/be1-go/internal/mocks/generator/federation.go similarity index 99% rename from be1-go/internal/mock/generatortest/federation.go rename to be1-go/internal/mocks/generator/federation.go index 0a440c51e6..d4c8680af9 100644 --- a/be1-go/internal/mock/generatortest/federation.go +++ b/be1-go/internal/mocks/generator/federation.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/generatortest.go b/be1-go/internal/mocks/generator/generatortest.go similarity index 98% rename from be1-go/internal/mock/generatortest/generatortest.go rename to be1-go/internal/mocks/generator/generatortest.go index b176e69933..840dd7eef0 100644 --- a/be1-go/internal/mock/generatortest/generatortest.go +++ b/be1-go/internal/mocks/generator/generatortest.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/base64" diff --git a/be1-go/internal/mock/generatortest/lao.go b/be1-go/internal/mocks/generator/lao.go similarity index 99% rename from be1-go/internal/mock/generatortest/lao.go rename to be1-go/internal/mocks/generator/lao.go index 49314d308b..59b747d8f7 100644 --- a/be1-go/internal/mock/generatortest/lao.go +++ b/be1-go/internal/mocks/generator/lao.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/query.go b/be1-go/internal/mocks/generator/query.go similarity index 99% rename from be1-go/internal/mock/generatortest/query.go rename to be1-go/internal/mocks/generator/query.go index 10fb47fd0d..f5b273a994 100644 --- a/be1-go/internal/mock/generatortest/query.go +++ b/be1-go/internal/mocks/generator/query.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/reaction.go b/be1-go/internal/mocks/generator/reaction.go similarity index 98% rename from be1-go/internal/mock/generatortest/reaction.go rename to be1-go/internal/mocks/generator/reaction.go index 03297460ef..b245d3f78b 100644 --- a/be1-go/internal/mock/generatortest/reaction.go +++ b/be1-go/internal/mocks/generator/reaction.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/mock/generatortest/root.go b/be1-go/internal/mocks/generator/root.go similarity index 96% rename from be1-go/internal/mock/generatortest/root.go rename to be1-go/internal/mocks/generator/root.go index 1bb4b3c3f4..2484dab608 100644 --- a/be1-go/internal/mock/generatortest/root.go +++ b/be1-go/internal/mocks/generator/root.go @@ -1,4 +1,4 @@ -package generatortest +package generator import ( "encoding/json" diff --git a/be1-go/internal/repository/mock_repository.go b/be1-go/internal/mocks/repository.go similarity index 82% rename from be1-go/internal/repository/mock_repository.go rename to be1-go/internal/mocks/repository.go index 1ad704d2df..e4fceb7456 100644 --- a/be1-go/internal/repository/mock_repository.go +++ b/be1-go/internal/mocks/repository.go @@ -1,26 +1,27 @@ // Code generated by mockery v2.42.1. DO NOT EDIT. -package repository +package mocks import ( messagedata "popstellar/internal/message/messagedata" message "popstellar/internal/message/query/method/message" - "popstellar/internal/types/election" kyber "go.dedis.ch/kyber/v3" method "popstellar/internal/message/query/method" mock "github.com/stretchr/testify/mock" + + types "popstellar/internal/types" ) -// MockRepository is an autogenerated mock type for the Repository type -type MockRepository struct { +// Repository is an autogenerated mock type for the Repository type +type Repository struct { mock.Mock } // AddMessageToMyRumor provides a mock function with given fields: messageID -func (_m *MockRepository) AddMessageToMyRumor(messageID string) (int, error) { +func (_m *Repository) AddMessageToMyRumor(messageID string) (int, error) { ret := _m.Called(messageID) if len(ret) == 0 { @@ -48,7 +49,7 @@ func (_m *MockRepository) AddMessageToMyRumor(messageID string) (int, error) { } // CheckPrevCreateOrCloseID provides a mock function with given fields: channel, nextID -func (_m *MockRepository) CheckPrevCreateOrCloseID(channel string, nextID string) (bool, error) { +func (_m *Repository) CheckPrevCreateOrCloseID(channel string, nextID string) (bool, error) { ret := _m.Called(channel, nextID) if len(ret) == 0 { @@ -76,7 +77,7 @@ func (_m *MockRepository) CheckPrevCreateOrCloseID(channel string, nextID string } // CheckPrevOpenOrReopenID provides a mock function with given fields: channel, nextID -func (_m *MockRepository) CheckPrevOpenOrReopenID(channel string, nextID string) (bool, error) { +func (_m *Repository) CheckPrevOpenOrReopenID(channel string, nextID string) (bool, error) { ret := _m.Called(channel, nextID) if len(ret) == 0 { @@ -104,7 +105,7 @@ func (_m *MockRepository) CheckPrevOpenOrReopenID(channel string, nextID string) } // CheckRumor provides a mock function with given fields: senderID, rumorID -func (_m *MockRepository) CheckRumor(senderID string, rumorID int) (bool, error) { +func (_m *Repository) CheckRumor(senderID string, rumorID int) (bool, error) { ret := _m.Called(senderID, rumorID) if len(ret) == 0 { @@ -132,7 +133,7 @@ func (_m *MockRepository) CheckRumor(senderID string, rumorID int) (bool, error) } // GetAllMessagesFromChannel provides a mock function with given fields: channelID -func (_m *MockRepository) GetAllMessagesFromChannel(channelID string) ([]message.Message, error) { +func (_m *Repository) GetAllMessagesFromChannel(channelID string) ([]message.Message, error) { ret := _m.Called(channelID) if len(ret) == 0 { @@ -162,7 +163,7 @@ func (_m *MockRepository) GetAllMessagesFromChannel(channelID string) ([]message } // GetAndIncrementMyRumor provides a mock function with given fields: -func (_m *MockRepository) GetAndIncrementMyRumor() (bool, method.Rumor, error) { +func (_m *Repository) GetAndIncrementMyRumor() (bool, method.Rumor, error) { ret := _m.Called() if len(ret) == 0 { @@ -197,7 +198,7 @@ func (_m *MockRepository) GetAndIncrementMyRumor() (bool, method.Rumor, error) { } // GetChannelType provides a mock function with given fields: channel -func (_m *MockRepository) GetChannelType(channel string) (string, error) { +func (_m *Repository) GetChannelType(channel string) (string, error) { ret := _m.Called(channel) if len(ret) == 0 { @@ -225,7 +226,7 @@ func (_m *MockRepository) GetChannelType(channel string) (string, error) { } // GetElectionAttendees provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionAttendees(electionID string) (map[string]struct{}, error) { +func (_m *Repository) GetElectionAttendees(electionID string) (map[string]struct{}, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -255,7 +256,7 @@ func (_m *MockRepository) GetElectionAttendees(electionID string) (map[string]st } // GetElectionCreationTime provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionCreationTime(electionID string) (int64, error) { +func (_m *Repository) GetElectionCreationTime(electionID string) (int64, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -283,23 +284,23 @@ func (_m *MockRepository) GetElectionCreationTime(electionID string) (int64, err } // GetElectionQuestions provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionQuestions(electionID string) (map[string]election.Question, error) { +func (_m *Repository) GetElectionQuestions(electionID string) (map[string]types.Question, error) { ret := _m.Called(electionID) if len(ret) == 0 { panic("no return value specified for GetElectionQuestions") } - var r0 map[string]election.Question + var r0 map[string]types.Question var r1 error - if rf, ok := ret.Get(0).(func(string) (map[string]election.Question, error)); ok { + if rf, ok := ret.Get(0).(func(string) (map[string]types.Question, error)); ok { return rf(electionID) } - if rf, ok := ret.Get(0).(func(string) map[string]election.Question); ok { + if rf, ok := ret.Get(0).(func(string) map[string]types.Question); ok { r0 = rf(electionID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]election.Question) + r0 = ret.Get(0).(map[string]types.Question) } } @@ -313,23 +314,23 @@ func (_m *MockRepository) GetElectionQuestions(electionID string) (map[string]el } // GetElectionQuestionsWithValidVotes provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionQuestionsWithValidVotes(electionID string) (map[string]election.Question, error) { +func (_m *Repository) GetElectionQuestionsWithValidVotes(electionID string) (map[string]types.Question, error) { ret := _m.Called(electionID) if len(ret) == 0 { panic("no return value specified for GetElectionQuestionsWithValidVotes") } - var r0 map[string]election.Question + var r0 map[string]types.Question var r1 error - if rf, ok := ret.Get(0).(func(string) (map[string]election.Question, error)); ok { + if rf, ok := ret.Get(0).(func(string) (map[string]types.Question, error)); ok { return rf(electionID) } - if rf, ok := ret.Get(0).(func(string) map[string]election.Question); ok { + if rf, ok := ret.Get(0).(func(string) map[string]types.Question); ok { r0 = rf(electionID) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]election.Question) + r0 = ret.Get(0).(map[string]types.Question) } } @@ -343,7 +344,7 @@ func (_m *MockRepository) GetElectionQuestionsWithValidVotes(electionID string) } // GetElectionSecretKey provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionSecretKey(electionID string) (kyber.Scalar, error) { +func (_m *Repository) GetElectionSecretKey(electionID string) (kyber.Scalar, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -373,7 +374,7 @@ func (_m *MockRepository) GetElectionSecretKey(electionID string) (kyber.Scalar, } // GetElectionType provides a mock function with given fields: electionID -func (_m *MockRepository) GetElectionType(electionID string) (string, error) { +func (_m *Repository) GetElectionType(electionID string) (string, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -401,7 +402,7 @@ func (_m *MockRepository) GetElectionType(electionID string) (string, error) { } // GetFederationExpect provides a mock function with given fields: senderPk, remotePk, Challenge, channelPath -func (_m *MockRepository) GetFederationExpect(senderPk string, remotePk string, Challenge messagedata.FederationChallenge, channelPath string) (messagedata.FederationExpect, error) { +func (_m *Repository) GetFederationExpect(senderPk string, remotePk string, Challenge messagedata.FederationChallenge, channelPath string) (messagedata.FederationExpect, error) { ret := _m.Called(senderPk, remotePk, Challenge, channelPath) if len(ret) == 0 { @@ -429,7 +430,7 @@ func (_m *MockRepository) GetFederationExpect(senderPk string, remotePk string, } // GetFederationInit provides a mock function with given fields: senderPk, remotePk, Challenge, channelPath -func (_m *MockRepository) GetFederationInit(senderPk string, remotePk string, Challenge messagedata.FederationChallenge, channelPath string) (messagedata.FederationInit, error) { +func (_m *Repository) GetFederationInit(senderPk string, remotePk string, Challenge messagedata.FederationChallenge, channelPath string) (messagedata.FederationInit, error) { ret := _m.Called(senderPk, remotePk, Challenge, channelPath) if len(ret) == 0 { @@ -457,7 +458,7 @@ func (_m *MockRepository) GetFederationInit(senderPk string, remotePk string, Ch } // GetLAOOrganizerPubKey provides a mock function with given fields: electionID -func (_m *MockRepository) GetLAOOrganizerPubKey(electionID string) (kyber.Point, error) { +func (_m *Repository) GetLAOOrganizerPubKey(electionID string) (kyber.Point, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -487,7 +488,7 @@ func (_m *MockRepository) GetLAOOrganizerPubKey(electionID string) (kyber.Point, } // GetLaoWitnesses provides a mock function with given fields: laoID -func (_m *MockRepository) GetLaoWitnesses(laoID string) (map[string]struct{}, error) { +func (_m *Repository) GetLaoWitnesses(laoID string) (map[string]struct{}, error) { ret := _m.Called(laoID) if len(ret) == 0 { @@ -517,7 +518,7 @@ func (_m *MockRepository) GetLaoWitnesses(laoID string) (map[string]struct{}, er } // GetMessageByID provides a mock function with given fields: ID -func (_m *MockRepository) GetMessageByID(ID string) (message.Message, error) { +func (_m *Repository) GetMessageByID(ID string) (message.Message, error) { ret := _m.Called(ID) if len(ret) == 0 { @@ -545,7 +546,7 @@ func (_m *MockRepository) GetMessageByID(ID string) (message.Message, error) { } // GetMessagesByID provides a mock function with given fields: IDs -func (_m *MockRepository) GetMessagesByID(IDs []string) (map[string]message.Message, error) { +func (_m *Repository) GetMessagesByID(IDs []string) (map[string]message.Message, error) { ret := _m.Called(IDs) if len(ret) == 0 { @@ -575,7 +576,7 @@ func (_m *MockRepository) GetMessagesByID(IDs []string) (map[string]message.Mess } // GetOrganizerPubKey provides a mock function with given fields: laoID -func (_m *MockRepository) GetOrganizerPubKey(laoID string) (kyber.Point, error) { +func (_m *Repository) GetOrganizerPubKey(laoID string) (kyber.Point, error) { ret := _m.Called(laoID) if len(ret) == 0 { @@ -605,7 +606,7 @@ func (_m *MockRepository) GetOrganizerPubKey(laoID string) (kyber.Point, error) } // GetParamsForGetMessageByID provides a mock function with given fields: params -func (_m *MockRepository) GetParamsForGetMessageByID(params map[string][]string) (map[string][]string, error) { +func (_m *Repository) GetParamsForGetMessageByID(params map[string][]string) (map[string][]string, error) { ret := _m.Called(params) if len(ret) == 0 { @@ -635,7 +636,7 @@ func (_m *MockRepository) GetParamsForGetMessageByID(params map[string][]string) } // GetParamsHeartbeat provides a mock function with given fields: -func (_m *MockRepository) GetParamsHeartbeat() (map[string][]string, error) { +func (_m *Repository) GetParamsHeartbeat() (map[string][]string, error) { ret := _m.Called() if len(ret) == 0 { @@ -665,7 +666,7 @@ func (_m *MockRepository) GetParamsHeartbeat() (map[string][]string, error) { } // GetReactionSender provides a mock function with given fields: messageID -func (_m *MockRepository) GetReactionSender(messageID string) (string, error) { +func (_m *Repository) GetReactionSender(messageID string) (string, error) { ret := _m.Called(messageID) if len(ret) == 0 { @@ -693,7 +694,7 @@ func (_m *MockRepository) GetReactionSender(messageID string) (string, error) { } // GetResultForGetMessagesByID provides a mock function with given fields: params -func (_m *MockRepository) GetResultForGetMessagesByID(params map[string][]string) (map[string][]message.Message, error) { +func (_m *Repository) GetResultForGetMessagesByID(params map[string][]string) (map[string][]message.Message, error) { ret := _m.Called(params) if len(ret) == 0 { @@ -723,7 +724,7 @@ func (_m *MockRepository) GetResultForGetMessagesByID(params map[string][]string } // GetRollCallState provides a mock function with given fields: channel -func (_m *MockRepository) GetRollCallState(channel string) (string, error) { +func (_m *Repository) GetRollCallState(channel string) (string, error) { ret := _m.Called(channel) if len(ret) == 0 { @@ -751,7 +752,7 @@ func (_m *MockRepository) GetRollCallState(channel string) (string, error) { } // GetServerKeys provides a mock function with given fields: -func (_m *MockRepository) GetServerKeys() (kyber.Point, kyber.Scalar, error) { +func (_m *Repository) GetServerKeys() (kyber.Point, kyber.Scalar, error) { ret := _m.Called() if len(ret) == 0 { @@ -790,7 +791,7 @@ func (_m *MockRepository) GetServerKeys() (kyber.Point, kyber.Scalar, error) { } // GetUnprocessedMessagesByChannel provides a mock function with given fields: -func (_m *MockRepository) GetUnprocessedMessagesByChannel() (map[string][]message.Message, error) { +func (_m *Repository) GetUnprocessedMessagesByChannel() (map[string][]message.Message, error) { ret := _m.Called() if len(ret) == 0 { @@ -820,7 +821,7 @@ func (_m *MockRepository) GetUnprocessedMessagesByChannel() (map[string][]messag } // HasChannel provides a mock function with given fields: channel -func (_m *MockRepository) HasChannel(channel string) (bool, error) { +func (_m *Repository) HasChannel(channel string) (bool, error) { ret := _m.Called(channel) if len(ret) == 0 { @@ -848,7 +849,7 @@ func (_m *MockRepository) HasChannel(channel string) (bool, error) { } // HasMessage provides a mock function with given fields: messageID -func (_m *MockRepository) HasMessage(messageID string) (bool, error) { +func (_m *Repository) HasMessage(messageID string) (bool, error) { ret := _m.Called(messageID) if len(ret) == 0 { @@ -876,7 +877,7 @@ func (_m *MockRepository) HasMessage(messageID string) (bool, error) { } // IsAttendee provides a mock function with given fields: laoPath, poptoken -func (_m *MockRepository) IsAttendee(laoPath string, poptoken string) (bool, error) { +func (_m *Repository) IsAttendee(laoPath string, poptoken string) (bool, error) { ret := _m.Called(laoPath, poptoken) if len(ret) == 0 { @@ -904,7 +905,7 @@ func (_m *MockRepository) IsAttendee(laoPath string, poptoken string) (bool, err } // IsChallengeValid provides a mock function with given fields: senderPk, challenge, channelPath -func (_m *MockRepository) IsChallengeValid(senderPk string, challenge messagedata.FederationChallenge, channelPath string) error { +func (_m *Repository) IsChallengeValid(senderPk string, challenge messagedata.FederationChallenge, channelPath string) error { ret := _m.Called(senderPk, challenge, channelPath) if len(ret) == 0 { @@ -922,7 +923,7 @@ func (_m *MockRepository) IsChallengeValid(senderPk string, challenge messagedat } // IsElectionEnded provides a mock function with given fields: electionID -func (_m *MockRepository) IsElectionEnded(electionID string) (bool, error) { +func (_m *Repository) IsElectionEnded(electionID string) (bool, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -950,7 +951,7 @@ func (_m *MockRepository) IsElectionEnded(electionID string) (bool, error) { } // IsElectionStarted provides a mock function with given fields: electionID -func (_m *MockRepository) IsElectionStarted(electionID string) (bool, error) { +func (_m *Repository) IsElectionStarted(electionID string) (bool, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -978,7 +979,7 @@ func (_m *MockRepository) IsElectionStarted(electionID string) (bool, error) { } // IsElectionStartedOrEnded provides a mock function with given fields: electionID -func (_m *MockRepository) IsElectionStartedOrEnded(electionID string) (bool, error) { +func (_m *Repository) IsElectionStartedOrEnded(electionID string) (bool, error) { ret := _m.Called(electionID) if len(ret) == 0 { @@ -1006,7 +1007,7 @@ func (_m *MockRepository) IsElectionStartedOrEnded(electionID string) (bool, err } // RemoveChallenge provides a mock function with given fields: challenge -func (_m *MockRepository) RemoveChallenge(challenge messagedata.FederationChallenge) error { +func (_m *Repository) RemoveChallenge(challenge messagedata.FederationChallenge) error { ret := _m.Called(challenge) if len(ret) == 0 { @@ -1024,7 +1025,7 @@ func (_m *MockRepository) RemoveChallenge(challenge messagedata.FederationChalle } // StoreChirpMessages provides a mock function with given fields: channel, generalChannel, msg, generalMsg -func (_m *MockRepository) StoreChirpMessages(channel string, generalChannel string, msg message.Message, generalMsg message.Message) error { +func (_m *Repository) StoreChirpMessages(channel string, generalChannel string, msg message.Message, generalMsg message.Message) error { ret := _m.Called(channel, generalChannel, msg, generalMsg) if len(ret) == 0 { @@ -1042,7 +1043,7 @@ func (_m *MockRepository) StoreChirpMessages(channel string, generalChannel stri } // StoreElection provides a mock function with given fields: laoPath, electionPath, electionPubKey, electionSecretKey, msg -func (_m *MockRepository) StoreElection(laoPath string, electionPath string, electionPubKey kyber.Point, electionSecretKey kyber.Scalar, msg message.Message) error { +func (_m *Repository) StoreElection(laoPath string, electionPath string, electionPubKey kyber.Point, electionSecretKey kyber.Scalar, msg message.Message) error { ret := _m.Called(laoPath, electionPath, electionPubKey, electionSecretKey, msg) if len(ret) == 0 { @@ -1060,7 +1061,7 @@ func (_m *MockRepository) StoreElection(laoPath string, electionPath string, ele } // StoreElectionEndWithResult provides a mock function with given fields: channelID, msg, electionResultMsg -func (_m *MockRepository) StoreElectionEndWithResult(channelID string, msg message.Message, electionResultMsg message.Message) error { +func (_m *Repository) StoreElectionEndWithResult(channelID string, msg message.Message, electionResultMsg message.Message) error { ret := _m.Called(channelID, msg, electionResultMsg) if len(ret) == 0 { @@ -1078,7 +1079,7 @@ func (_m *MockRepository) StoreElectionEndWithResult(channelID string, msg messa } // StoreElectionWithElectionKey provides a mock function with given fields: laoPath, electionPath, electionPubKey, electionSecretKey, msg, electionKeyMsg -func (_m *MockRepository) StoreElectionWithElectionKey(laoPath string, electionPath string, electionPubKey kyber.Point, electionSecretKey kyber.Scalar, msg message.Message, electionKeyMsg message.Message) error { +func (_m *Repository) StoreElectionWithElectionKey(laoPath string, electionPath string, electionPubKey kyber.Point, electionSecretKey kyber.Scalar, msg message.Message, electionKeyMsg message.Message) error { ret := _m.Called(laoPath, electionPath, electionPubKey, electionSecretKey, msg, electionKeyMsg) if len(ret) == 0 { @@ -1096,7 +1097,7 @@ func (_m *MockRepository) StoreElectionWithElectionKey(laoPath string, electionP } // StoreLaoWithLaoGreet provides a mock function with given fields: channels, laoID, organizerPubBuf, msg, laoGreetMsg -func (_m *MockRepository) StoreLaoWithLaoGreet(channels map[string]string, laoID string, organizerPubBuf []byte, msg message.Message, laoGreetMsg message.Message) error { +func (_m *Repository) StoreLaoWithLaoGreet(channels map[string]string, laoID string, organizerPubBuf []byte, msg message.Message, laoGreetMsg message.Message) error { ret := _m.Called(channels, laoID, organizerPubBuf, msg, laoGreetMsg) if len(ret) == 0 { @@ -1114,7 +1115,7 @@ func (_m *MockRepository) StoreLaoWithLaoGreet(channels map[string]string, laoID } // StoreMessageAndData provides a mock function with given fields: channelID, msg -func (_m *MockRepository) StoreMessageAndData(channelID string, msg message.Message) error { +func (_m *Repository) StoreMessageAndData(channelID string, msg message.Message) error { ret := _m.Called(channelID, msg) if len(ret) == 0 { @@ -1132,7 +1133,7 @@ func (_m *MockRepository) StoreMessageAndData(channelID string, msg message.Mess } // StoreRollCallClose provides a mock function with given fields: channels, laoID, msg -func (_m *MockRepository) StoreRollCallClose(channels []string, laoID string, msg message.Message) error { +func (_m *Repository) StoreRollCallClose(channels []string, laoID string, msg message.Message) error { ret := _m.Called(channels, laoID, msg) if len(ret) == 0 { @@ -1150,7 +1151,7 @@ func (_m *MockRepository) StoreRollCallClose(channels []string, laoID string, ms } // StoreRumor provides a mock function with given fields: rumorID, sender, unprocessed, processed -func (_m *MockRepository) StoreRumor(rumorID int, sender string, unprocessed map[string][]message.Message, processed []string) error { +func (_m *Repository) StoreRumor(rumorID int, sender string, unprocessed map[string][]message.Message, processed []string) error { ret := _m.Called(rumorID, sender, unprocessed, processed) if len(ret) == 0 { @@ -1168,7 +1169,7 @@ func (_m *MockRepository) StoreRumor(rumorID int, sender string, unprocessed map } // StoreServerKeys provides a mock function with given fields: electionPubKey, electionSecretKey -func (_m *MockRepository) StoreServerKeys(electionPubKey kyber.Point, electionSecretKey kyber.Scalar) error { +func (_m *Repository) StoreServerKeys(electionPubKey kyber.Point, electionSecretKey kyber.Scalar) error { ret := _m.Called(electionPubKey, electionSecretKey) if len(ret) == 0 { @@ -1185,13 +1186,13 @@ func (_m *MockRepository) StoreServerKeys(electionPubKey kyber.Point, electionSe return r0 } -// NewMockRepository creates a new instance of MockRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// NewRepository creates a new instance of Repository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewMockRepository(t interface { +func NewRepository(t interface { mock.TestingT Cleanup(func()) -}) *MockRepository { - mock := &MockRepository{} +}) *Repository { + mock := &Repository{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/be1-go/internal/repository/repository.go b/be1-go/internal/repository/repository.go index 6c0a23020b..caa1541e48 100644 --- a/be1-go/internal/repository/repository.go +++ b/be1-go/internal/repository/repository.go @@ -5,7 +5,7 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/types/election" + "popstellar/internal/types" ) type Repository interface { @@ -169,10 +169,10 @@ type ElectionRepository interface { GetElectionAttendees(electionID string) (map[string]struct{}, error) // GetElectionQuestions returns the questions of an election. - GetElectionQuestions(electionID string) (map[string]election.Question, error) + GetElectionQuestions(electionID string) (map[string]types.Question, error) // GetElectionQuestionsWithValidVotes returns the questions of an election with valid votes. - GetElectionQuestionsWithValidVotes(electionID string) (map[string]election.Question, error) + GetElectionQuestionsWithValidVotes(electionID string) (map[string]types.Question, error) // StoreElectionEndWithResult stores a message and an election result message inside the database. StoreElectionEndWithResult(channelID string, msg, electionResultMsg message.Message) error diff --git a/be1-go/internal/singleton/database/database.go b/be1-go/internal/singleton/database/database.go index 6f7cbde70f..3a9f1d845e 100644 --- a/be1-go/internal/singleton/database/database.go +++ b/be1-go/internal/singleton/database/database.go @@ -2,6 +2,7 @@ package database import ( "popstellar/internal/message/answer" + "popstellar/internal/mocks" repository2 "popstellar/internal/repository" "sync" ) @@ -17,7 +18,7 @@ func InitDatabase(db repository2.Repository) { // ONLY FOR TEST PURPOSE // SetDatabase is only here to be used to reset the database before each test -func SetDatabase(mockRepo *repository2.MockRepository) { +func SetDatabase(mockRepo *mocks.Repository) { instance = mockRepo } diff --git a/be1-go/internal/singleton/state/state.go b/be1-go/internal/singleton/state/state.go index 26103ed61c..df1331a9e0 100644 --- a/be1-go/internal/singleton/state/state.go +++ b/be1-go/internal/singleton/state/state.go @@ -3,11 +3,7 @@ package state import ( "github.com/rs/zerolog" "popstellar/internal/message/answer" - "popstellar/internal/types/hubparams" - "popstellar/internal/types/peers" - "popstellar/internal/types/queries" - "popstellar/internal/types/sockets" - types2 "popstellar/internal/types/subscribers" + "popstellar/internal/types" "sync" ) @@ -26,11 +22,11 @@ type state struct { func InitState(log *zerolog.Logger) { once.Do(func() { instance = &state{ - subs: types2.NewSubscribers(), - peers: peers.NewPeers(), - queries: queries.NewQueries(log), - hubParams: hubparams.NewHubParams(), - sockets: sockets.NewSockets(), + subs: types.NewSubscribers(), + peers: types.NewPeers(), + queries: types.NewQueries(log), + hubParams: types.NewHubParams(), + sockets: types.NewSockets(), resetRumorSender: make(chan struct{}), } }) diff --git a/be1-go/internal/sqlite/sqlite.go b/be1-go/internal/sqlite/sqlite.go index 9ed760b6ac..fe9709205a 100644 --- a/be1-go/internal/sqlite/sqlite.go +++ b/be1-go/internal/sqlite/sqlite.go @@ -14,7 +14,7 @@ import ( "popstellar/internal/message/query" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/types/election" + "popstellar/internal/types" "strings" "time" ) @@ -1008,7 +1008,7 @@ func (s *SQLite) getElectionSetup(electionPath string, tx *sql.Tx) (messagedata. } -func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]election.Question, error) { +func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]types.Question, error) { dbLock.Lock() defer dbLock.Unlock() @@ -1037,7 +1037,7 @@ func (s *SQLite) GetElectionQuestions(electionPath string) (map[string]election. return questions, nil } -func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[string]election.Question, error) { +func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[string]types.Question, error) { dbLock.Lock() defer dbLock.Unlock() @@ -1089,8 +1089,8 @@ func (s *SQLite) GetElectionQuestionsWithValidVotes(electionPath string) (map[st return questions, nil } -func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[string]election.Question, error) { - questions := make(map[string]election.Question) +func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[string]types.Question, error) { + questions := make(map[string]types.Question) for _, question := range electionSetup.Questions { ballotOptions := make([]string, len(question.BallotOptions)) copy(ballotOptions, question.BallotOptions) @@ -1098,17 +1098,17 @@ func getQuestionsFromMessage(electionSetup messagedata.ElectionSetup) (map[strin if ok { return nil, xerrors.Errorf("duplicate question ID") } - questions[question.ID] = election.Question{ + questions[question.ID] = types.Question{ ID: []byte(question.ID), BallotOptions: ballotOptions, - ValidVotes: make(map[string]election.ValidVote), + ValidVotes: make(map[string]types.ValidVote), Method: question.VotingMethod, } } return questions, nil } -func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questions map[string]election.Question) error { +func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questions map[string]types.Question) error { for idx, vote := range castVote.Votes { question, ok := questions[vote.Question] if !ok { @@ -1116,7 +1116,7 @@ func updateVote(msgID, sender string, castVote messagedata.VoteCastVote, questio } earlierVote, ok := question.ValidVotes[sender] if !ok || earlierVote.VoteTime < castVote.CreatedAt { - question.ValidVotes[sender] = election.ValidVote{ + question.ValidVotes[sender] = types.ValidVote{ MsgID: msgID, ID: vote.ID, VoteTime: castVote.CreatedAt, diff --git a/be1-go/internal/sqlite/sqlite_test.go b/be1-go/internal/sqlite/sqlite_test.go index 6f8baba962..50cc7eae0a 100644 --- a/be1-go/internal/sqlite/sqlite_test.go +++ b/be1-go/internal/sqlite/sqlite_test.go @@ -11,8 +11,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mock/generatortest" - "popstellar/internal/types/election" + "popstellar/internal/mocks/generator" + "popstellar/internal/types" "sort" "testing" "time" @@ -318,7 +318,7 @@ func Test_SQLite_StoreLaoWithLaoGreet(t *testing.T) { laoID := "laoID" - laoCreateMsg := generatortest.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, + laoCreateMsg := generator.NewLaoCreateMsg(t, "sender1", laoID, "laoName", 123456789, organizerPubBuf64, nil) laoGreet := messagedata.LaoGreet{ @@ -389,9 +389,9 @@ func Test_SQLite_GetRollCallState(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generator.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallOpen := generator.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallClose := generator.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) states := []string{"create", "open", "close"} messages := []message.Message{rollCallCreate, rollCallOpen, rollCallClose} @@ -410,8 +410,8 @@ func Test_SQLite_CheckPrevOpenOrReopenID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallOpen := generatortest.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) - rollCallReopen := generatortest.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) + rollCallOpen := generator.NewRollCallOpenMsg(t, "sender1", "openID", "createID", 4, nil) + rollCallReopen := generator.NewRollCallReOpenMsg(t, "sender1", "reopenID", "closeID", 12, nil) err = lite.StoreMessageAndData("channel1", rollCallOpen) require.NoError(t, err) @@ -434,8 +434,8 @@ func Test_SQLite_CheckPrevCreateOrCloseID(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - rollCallCreate := generatortest.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallCreate := generator.NewRollCallCreateMsg(t, "sender1", "name", "createID", 1, 2, 10, nil) + rollCallClose := generator.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreMessageAndData("channel1", rollCallCreate) require.NoError(t, err) @@ -461,7 +461,7 @@ func Test_SQLite_StoreRollCallClose(t *testing.T) { channels := []string{"channel1", "channel2", "channel3"} laoID := "laoID" - rollCallClose := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) + rollCallClose := generator.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, nil, nil) err = lite.StoreRollCallClose(channels, laoID, rollCallClose) require.NoError(t, err) @@ -492,7 +492,7 @@ func Test_SQLite_StoreElectionWithElectionKey(t *testing.T) { electionPubBuf, err := point.MarshalBinary() require.NoError(t, err) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generator.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) electionKey := messagedata.ElectionKey{ @@ -542,7 +542,7 @@ func Test_SQLite_StoreElection(t *testing.T) { secret := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) point := crypto.Suite.Point().Mul(secret, nil) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", + electionSetupMsg := generator.NewElectionSetupMsg(t, "sender1", "ID1", laoID, "electionName", "version", 1, 2, 3, nil, nil) err = lite.StoreElection(laoID, electionID, point, secret, electionSetupMsg) @@ -576,7 +576,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionOpenMsg := generatortest.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) + electionOpenMsg := generator.NewElectionOpenMsg(t, "sender1", laoID, electionID, 1, nil) err = lite.StoreMessageAndData(electionID, electionOpenMsg) require.NoError(t, err) @@ -592,7 +592,7 @@ func Test_SQLite_IsElectionStartedOrTerminated(t *testing.T) { require.NoError(t, err) require.False(t, ok) - electionCloseMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionCloseMsg := generator.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) err = lite.StoreMessageAndData(electionID, electionCloseMsg) require.NoError(t, err) @@ -619,7 +619,7 @@ func Test_SQLite_GetElectionCreationTimeAndType(t *testing.T) { electionPath := "electionPath" creationTime := int64(123456789) - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generator.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, creationTime, 2, 3, nil, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -645,7 +645,7 @@ func Test_SQLite_GetElectionAttendees(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} expected := map[string]struct{}{"attendee1": {}, "attendee2": {}, "attendee3": {}} - rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) + rollCallCloseMsg := generator.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) require.NoError(t, err) @@ -677,7 +677,7 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { }, } - electionSetupMsg := generatortest.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", + electionSetupMsg := generator.NewElectionSetupMsg(t, "sender1", "ID1", laoPath, "electionName", messagedata.OpenBallot, 1, 2, 3, questions, nil) err = lite.StoreMessageAndData(electionPath, electionSetupMsg) @@ -694,16 +694,16 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.NoError(t, err) // Add votes to the election - vote1 := generatortest.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} - votes := []generatortest.VoteString{vote1} - castVoteMsg := generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote1 := generator.VoteString{ID: "voteID1", Question: "questionID1", Vote: "Option1"} + votes := []generator.VoteString{vote1} + castVoteMsg := generator.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 1, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) require.NoError(t, err) question1 := expected["questionID1"] - question1.ValidVotes = map[string]election.ValidVote{ + question1.ValidVotes = map[string]types.ValidVote{ "sender1": {MsgID: castVoteMsg.MessageID, ID: "voteID1", VoteTime: 1, Index: "Option1"}, } expected["questionID1"] = question1 @@ -713,16 +713,16 @@ func Test_SQLite_GetElectionQuestionsWithVotes(t *testing.T) { require.Equal(t, expected, result) // Add more votes to the election - vote2 := generatortest.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} - votes = []generatortest.VoteString{vote2} - castVoteMsg = generatortest.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, + vote2 := generator.VoteString{ID: "voteID2", Question: "questionID1", Vote: "Option2"} + votes = []generator.VoteString{vote2} + castVoteMsg = generator.NewVoteCastVoteStringMsg(t, "sender1", laoID, electionID, 2, votes, nil) err = lite.StoreMessageAndData(electionPath, castVoteMsg) require.NoError(t, err) question1 = expected["questionID1"] - question1.ValidVotes = map[string]election.ValidVote{ + question1.ValidVotes = map[string]types.ValidVote{ "sender1": {MsgID: castVoteMsg.MessageID, ID: "voteID2", VoteTime: 2, Index: "Option2"}, } expected["questionID1"] = question1 @@ -742,8 +742,8 @@ func Test_SQLite_StoreElectionEndWithResult(t *testing.T) { laoID := "laoID" electionID := "electionID" - electionEndMsg := generatortest.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) - electionResultMsg := generatortest.NewElectionResultMsg(t, "sender2", nil, nil) + electionEndMsg := generator.NewElectionCloseMsg(t, "sender1", laoID, electionID, "", 1, nil) + electionResultMsg := generator.NewElectionResultMsg(t, "sender2", nil, nil) err = lite.StoreElectionEndWithResult(electionPath, electionEndMsg, electionResultMsg) require.NoError(t, err) @@ -763,7 +763,7 @@ func Test_SQLite_StoreChirpMessages(t *testing.T) { chirpPath := "chirpID" generalChirpPath := "generalChirpID" - chirpMsg := generatortest.NewChirpAddMsg(t, "sender1", nil, 1) + chirpMsg := generator.NewChirpAddMsg(t, "sender1", nil, 1) generalChirpMsg := message.Message{ Data: base64.URLEncoding.EncodeToString([]byte("data")), Sender: "sender1", @@ -795,7 +795,7 @@ func Test_SQLite_IsAttendee(t *testing.T) { attendees := []string{"attendee1", "attendee2", "attendee3"} laoID := "laoID" - rollCallCloseMsg := generatortest.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", + rollCallCloseMsg := generator.NewRollCallCloseMsg(t, "sender1", "closeID", "openID", 8, attendees, nil) err = lite.StoreMessageAndData(laoID, rollCallCloseMsg) @@ -817,7 +817,7 @@ func Test_SQLite_GetReactionSender(t *testing.T) { defer lite.Close() defer os.RemoveAll(dir) - reactionAddMsg := generatortest.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) + reactionAddMsg := generator.NewReactionAddMsg(t, "sender1", nil, "", "chirpID", 1) sender, err := lite.GetReactionSender(reactionAddMsg.MessageID) require.NoError(t, err) @@ -849,7 +849,7 @@ func Test_SQLite_IsChallengeValid(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, sender, value, + challengeMsg := generator.NewFederationChallenge(t, sender, value, validUntil, nil) err = lite.StoreMessageAndData(fedPath, challengeMsg) @@ -894,10 +894,10 @@ func Test_SQLite_GetFederationExpect(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generator.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest.NewFederationExpect(t, organizer, laoId, + expectMsg := generator.NewFederationExpect(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationExpect(organizer, organizer2, challenge, fedPath) @@ -940,10 +940,10 @@ func Test_SQLite_GetFederationInit(t *testing.T) { ValidUntil: validUntil, } - challengeMsg := generatortest.NewFederationChallenge(t, organizer, value, + challengeMsg := generator.NewFederationChallenge(t, organizer, value, validUntil, nil) - expectMsg := generatortest.NewFederationInit(t, organizer, laoId, + expectMsg := generator.NewFederationInit(t, organizer, laoId, serverAddressA, organizer2, challengeMsg, nil) _, err = lite.GetFederationInit(organizer, organizer2, challenge, fedPath) diff --git a/be1-go/internal/types/hubparams/hub_params.go b/be1-go/internal/types/hub_params.go similarity index 97% rename from be1-go/internal/types/hubparams/hub_params.go rename to be1-go/internal/types/hub_params.go index 449dbdf408..e4d49226a7 100644 --- a/be1-go/internal/types/hubparams/hub_params.go +++ b/be1-go/internal/types/hub_params.go @@ -1,4 +1,4 @@ -package hubparams +package types import ( "popstellar/internal/network/socket" diff --git a/be1-go/internal/types/peers/peers.go b/be1-go/internal/types/peers.go similarity index 99% rename from be1-go/internal/types/peers/peers.go rename to be1-go/internal/types/peers.go index 88ec7695bf..37b2ba01a4 100644 --- a/be1-go/internal/types/peers/peers.go +++ b/be1-go/internal/types/peers.go @@ -1,4 +1,4 @@ -package peers +package types import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/types/queries/queries.go b/be1-go/internal/types/queries.go similarity index 99% rename from be1-go/internal/types/queries/queries.go rename to be1-go/internal/types/queries.go index 07bed48ea5..7c58c93956 100644 --- a/be1-go/internal/types/queries/queries.go +++ b/be1-go/internal/types/queries.go @@ -1,4 +1,4 @@ -package queries +package types import ( "popstellar/internal/message/query/method" diff --git a/be1-go/internal/types/election/question.go b/be1-go/internal/types/question.go similarity index 97% rename from be1-go/internal/types/election/question.go rename to be1-go/internal/types/question.go index 4710116b21..c44f5e222d 100644 --- a/be1-go/internal/types/election/question.go +++ b/be1-go/internal/types/question.go @@ -1,4 +1,4 @@ -package election +package types type Question struct { // ID represents the ID of the Question. diff --git a/be1-go/internal/types/sockets/sockets.go b/be1-go/internal/types/sockets.go similarity index 99% rename from be1-go/internal/types/sockets/sockets.go rename to be1-go/internal/types/sockets.go index a4d6b761ab..aa76b45bfa 100644 --- a/be1-go/internal/types/sockets/sockets.go +++ b/be1-go/internal/types/sockets.go @@ -1,4 +1,4 @@ -package sockets +package types import ( "fmt" diff --git a/be1-go/internal/types/subscribers/subscribers.go b/be1-go/internal/types/subscribers.go similarity index 99% rename from be1-go/internal/types/subscribers/subscribers.go rename to be1-go/internal/types/subscribers.go index 6c89139028..5ff06dd7ec 100644 --- a/be1-go/internal/types/subscribers/subscribers.go +++ b/be1-go/internal/types/subscribers.go @@ -1,4 +1,4 @@ -package subscribers +package types import ( "fmt" diff --git a/be1-go/internal/types/uint53/uint53.go b/be1-go/internal/types/uint53.go similarity index 98% rename from be1-go/internal/types/uint53/uint53.go rename to be1-go/internal/types/uint53.go index 403a0d688e..30f32fc8ad 100644 --- a/be1-go/internal/types/uint53/uint53.go +++ b/be1-go/internal/types/uint53.go @@ -3,7 +3,7 @@ // These values can be handled without loss of precision in IEEE754 64-bit // floating-point numbers, and thus in JSON. -package uint53 +package types import ( "errors" diff --git a/be1-go/internal/types/uint53/uint53_test.go b/be1-go/internal/types/uint53_test.go similarity index 98% rename from be1-go/internal/types/uint53/uint53_test.go rename to be1-go/internal/types/uint53_test.go index 566a5c78d6..bcb3770578 100644 --- a/be1-go/internal/types/uint53/uint53_test.go +++ b/be1-go/internal/types/uint53_test.go @@ -1,4 +1,4 @@ -package uint53 +package types import ( "testing" From ad0e85649b7684d18c1026a06de54eed42d76157 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 15:22:35 +0200 Subject: [PATCH 05/19] create a new file for the mid level check --- be1-go/internal/handler/answer.go | 10 +- be1-go/internal/handler/channel.go | 60 +-------- be1-go/internal/handler/channel_test.go | 105 +-------------- be1-go/internal/handler/incoming_message.go | 4 +- be1-go/internal/handler/message.go | 72 ++++++++++ be1-go/internal/handler/message_test.go | 142 ++++++++++++++++++++ be1-go/internal/handler/publish.go | 2 +- be1-go/internal/handler/query.go | 6 +- be1-go/internal/handler/query_test.go | 2 +- be1-go/internal/handler/rumor.go | 2 +- 10 files changed, 232 insertions(+), 173 deletions(-) create mode 100644 be1-go/internal/handler/message.go create mode 100644 be1-go/internal/handler/message_test.go diff --git a/be1-go/internal/handler/answer.go b/be1-go/internal/handler/answer.go index ca7346a387..3f919891a8 100644 --- a/be1-go/internal/handler/answer.go +++ b/be1-go/internal/handler/answer.go @@ -15,13 +15,13 @@ const ( continueMongering = 0.5 ) -func handleAnswer(msg []byte) *answer.Error { +func HandleAnswer(msg []byte) *answer.Error { var answerMsg answer.Answer err := json.Unmarshal(msg, &answerMsg) if err != nil { errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return errAnswer.Wrap("handleAnswer") + return errAnswer.Wrap("HandleAnswer") } isRumor, errAnswer := state.IsRumorQuery(*answerMsg.ID) @@ -46,12 +46,12 @@ func handleAnswer(msg []byte) *answer.Error { errAnswer = state.SetQueryReceived(*answerMsg.ID) if errAnswer != nil { - return errAnswer.Wrap("handleAnswer") + return errAnswer.Wrap("HandleAnswer") } errAnswer = handleGetMessagesByIDAnswer(answerMsg) if errAnswer != nil { - return errAnswer.Wrap("handleAnswer") + return errAnswer.Wrap("HandleAnswer") } return nil @@ -144,7 +144,7 @@ func tryToHandleMessages(msgsByChannel map[string]map[string]message.Message, so for _, channelID := range sortedChannelIDs { msgs := msgsByChannel[channelID] for msgID, msg := range msgs { - errAnswer := handleChannel(channelID, msg, false) + errAnswer := HandleMessage(channelID, msg, false) if errAnswer == nil { delete(msgsByChannel[channelID], msgID) continue diff --git a/be1-go/internal/handler/channel.go b/be1-go/internal/handler/channel.go index 062643495c..3105f64839 100644 --- a/be1-go/internal/handler/channel.go +++ b/be1-go/internal/handler/channel.go @@ -20,34 +20,16 @@ import ( "popstellar/internal/validation" ) -func handleChannel(channelPath string, msg message.Message, fromRumor bool) *answer.Error { - errAnswer := verifyMessage(msg) - if errAnswer != nil { - return errAnswer.Wrap("handleChannel") - } - +func HandleChannel(channelPath string, msg message.Message) *answer.Error { db, errAnswer := database.GetChannelRepositoryInstance() if errAnswer != nil { - return errAnswer.Wrap("handleChannel") - } - - msgAlreadyExists, err := db.HasMessage(msg.MessageID) - if err != nil { - errAnswer := answer.NewQueryDatabaseError("if message exists: %v", err) - return errAnswer.Wrap("handleChannel") - } - if msgAlreadyExists && fromRumor { - return nil - } - if msgAlreadyExists { - errAnswer := answer.NewInvalidActionError("message %s was already received", msg.MessageID) - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } channelType, err := db.GetChannelType(channelPath) if err != nil { errAnswer := answer.NewQueryDatabaseError("channel type: %v", err) - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } switch channelType { @@ -70,7 +52,7 @@ func handleChannel(channelPath string, msg message.Message, fromRumor bool) *ans } if errAnswer != nil { - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } return nil @@ -78,40 +60,6 @@ func handleChannel(channelPath string, msg message.Message, fromRumor bool) *ans // util for the channels -func verifyMessage(msg message.Message) *answer.Error { - dataBytes, err := base64.URLEncoding.DecodeString(msg.Data) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode data: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - publicKeySender, err := base64.URLEncoding.DecodeString(msg.Sender) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode public key: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - signatureBytes, err := base64.URLEncoding.DecodeString(msg.Signature) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode signature: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - err = schnorr.VerifyWithChecks(crypto.Suite, publicKeySender, dataBytes, signatureBytes) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to verify signature : %v", err) - return errAnswer.Wrap("verifyMessage") - } - - expectedMessageID := messagedata.Hash(msg.Data, msg.Signature) - if expectedMessageID != msg.MessageID { - errAnswer := answer.NewInvalidActionError("messageID is wrong: expected %s found %s", - expectedMessageID, msg.MessageID) - return errAnswer.Wrap("verifyMessage") - } - return nil -} - func verifyDataAndGetObjectAction(msg message.Message) (string, string, *answer.Error) { jsonData, err := base64.URLEncoding.DecodeString(msg.Data) if err != nil { diff --git a/be1-go/internal/handler/channel_test.go b/be1-go/internal/handler/channel_test.go index 7e4df3eeda..452c0e841d 100644 --- a/be1-go/internal/handler/channel_test.go +++ b/be1-go/internal/handler/channel_test.go @@ -64,112 +64,9 @@ func Test_handleChannel(t *testing.T) { contains: "DB is disconnected", }) - // Test 3: failed to handled message because message already exists - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - - mockRepository.On("HasMessage", msg.MessageID).Return(true, nil) - - args = append(args, input{ - name: "Test 3", - message: msg, - contains: "message " + msg.MessageID + " was already received", - }) - - // Test 4: failed to handled message because db is disconnected when querying if the message already exists - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - - mockRepository.On("HasMessage", msg.MessageID). - Return(false, xerrors.Errorf("DB is disconnected")) - - args = append(args, input{ - name: "Test 4", - message: msg, - contains: "DB is disconnected", - }) - - // Test 5: failed to handled message because the format of messageID - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - expectedMsgID := msg.MessageID - msg.MessageID = base64.URLEncoding.EncodeToString([]byte("wrong messageID")) - - args = append(args, input{ - name: "Test 5", - message: msg, - contains: "messageID is wrong: expected " + expectedMsgID + " found " + msg.MessageID, - }) - - // Test 6: failed to handled message because wrong sender - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Sender = base64.URLEncoding.EncodeToString([]byte("wrong sender")) - - args = append(args, input{ - name: "Test 6", - message: msg, - contains: "failed to verify signature", - }) - - // Test 7: failed to handled message because wrong data - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong data")) - - args = append(args, input{ - name: "Test 7", - message: msg, - contains: "failed to verify signature", - }) - - // Test 8: failed to handled message because wrong signature - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong signature")) - - args = append(args, input{ - name: "Test 8", - message: msg, - contains: "failed to verify signature", - }) - - // Test 9: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Signature = "wrong signature" - - args = append(args, input{ - name: "Test 9", - message: msg, - contains: "failed to decode signature", - }) - - // Test 10: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Sender = "wrong sender" - - args = append(args, input{ - name: "Test 10", - message: msg, - contains: "failed to decode public key", - }) - - // Test 11: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = "wrong data" - - args = append(args, input{ - name: "Test 11", - message: msg, - contains: "failed to decode data", - }) - for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannel(arg.channel, arg.message, false) + errAnswer := HandleMessage(arg.channel, arg.message, false) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/incoming_message.go b/be1-go/internal/handler/incoming_message.go index 1b9d048e46..52024607e1 100644 --- a/be1-go/internal/handler/incoming_message.go +++ b/be1-go/internal/handler/incoming_message.go @@ -25,9 +25,9 @@ func HandleIncomingMessage(socket socket.Socket, msg []byte) error { switch rpcType { case message.RPCTypeQuery: - errAnswer = handleQuery(socket, msg) + errAnswer = HandleQuery(socket, msg) case message.RPCTypeAnswer: - errAnswer = handleAnswer(msg) + errAnswer = HandleAnswer(msg) default: errAnswer = answer.NewInvalidMessageFieldError("jsonRPC is of unknown type") } diff --git a/be1-go/internal/handler/message.go b/be1-go/internal/handler/message.go new file mode 100644 index 0000000000..3e17213f78 --- /dev/null +++ b/be1-go/internal/handler/message.go @@ -0,0 +1,72 @@ +package handler + +import ( + "encoding/base64" + "go.dedis.ch/kyber/v3/sign/schnorr" + "popstellar/internal/crypto" + "popstellar/internal/message/answer" + "popstellar/internal/message/messagedata" + "popstellar/internal/message/query/method/message" + "popstellar/internal/singleton/database" +) + +func HandleMessage(channelPath string, msg message.Message, fromRumor bool) *answer.Error { + errAnswer := verifyMessage(msg) + if errAnswer != nil { + return errAnswer.Wrap("HandleMessage") + } + + db, errAnswer := database.GetChannelRepositoryInstance() + if errAnswer != nil { + return errAnswer.Wrap("HandleMessage") + } + + msgAlreadyExists, err := db.HasMessage(msg.MessageID) + if err != nil { + errAnswer := answer.NewQueryDatabaseError("if message exists: %v", err) + return errAnswer.Wrap("HandleMessage") + } + if msgAlreadyExists && fromRumor { + return nil + } + if msgAlreadyExists { + errAnswer := answer.NewInvalidActionError("message %s was already received", msg.MessageID) + return errAnswer.Wrap("HandleMessage") + } + + return HandleChannel(channelPath, msg) +} + +func verifyMessage(msg message.Message) *answer.Error { + dataBytes, err := base64.URLEncoding.DecodeString(msg.Data) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode data: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + publicKeySender, err := base64.URLEncoding.DecodeString(msg.Sender) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode public key: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + signatureBytes, err := base64.URLEncoding.DecodeString(msg.Signature) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode signature: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + err = schnorr.VerifyWithChecks(crypto.Suite, publicKeySender, dataBytes, signatureBytes) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to verify signature : %v", err) + return errAnswer.Wrap("verifyMessage") + } + + expectedMessageID := messagedata.Hash(msg.Data, msg.Signature) + if expectedMessageID != msg.MessageID { + errAnswer := answer.NewInvalidActionError("messageID is wrong: expected %s found %s", + expectedMessageID, msg.MessageID) + return errAnswer.Wrap("verifyMessage") + } + return nil +} diff --git a/be1-go/internal/handler/message_test.go b/be1-go/internal/handler/message_test.go new file mode 100644 index 0000000000..05596fc72f --- /dev/null +++ b/be1-go/internal/handler/message_test.go @@ -0,0 +1,142 @@ +package handler + +import ( + "encoding/base64" + "github.com/stretchr/testify/require" + "golang.org/x/xerrors" + "popstellar/internal/message/query/method/message" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/database" + "testing" + "time" +) + +func Test_handleMessage(t *testing.T) { + mockRepository := mocks.NewRepository(t) + database.SetDatabase(mockRepository) + + keypair := GenerateKeyPair(t) + sender := base64.URLEncoding.EncodeToString(keypair.PublicBuf) + + type input struct { + name string + channel string + message message.Message + contains string + } + + args := make([]input, 0) + + // Test 1: failed to handled message because message already exists + + msg := generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + + mockRepository.On("HasMessage", msg.MessageID).Return(true, nil) + + args = append(args, input{ + name: "Test 1", + message: msg, + contains: "message " + msg.MessageID + " was already received", + }) + + // Test 2: failed to handled message because db is disconnected when querying if the message already exists + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + + mockRepository.On("HasMessage", msg.MessageID). + Return(false, xerrors.Errorf("DB is disconnected")) + + args = append(args, input{ + name: "Test 2", + message: msg, + contains: "DB is disconnected", + }) + + // Test 3: failed to handled message because the format of messageID + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + expectedMsgID := msg.MessageID + msg.MessageID = base64.URLEncoding.EncodeToString([]byte("wrong messageID")) + + args = append(args, input{ + name: "Test 3", + message: msg, + contains: "messageID is wrong: expected " + expectedMsgID + " found " + msg.MessageID, + }) + + // Test 4: failed to handled message because wrong sender + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Sender = base64.URLEncoding.EncodeToString([]byte("wrong sender")) + + args = append(args, input{ + name: "Test 4", + message: msg, + contains: "failed to verify signature", + }) + + // Test 5: failed to handled message because wrong data + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong data")) + + args = append(args, input{ + name: "Test 5", + message: msg, + contains: "failed to verify signature", + }) + + // Test 6: failed to handled message because wrong signature + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong signature")) + + args = append(args, input{ + name: "Test 6", + message: msg, + contains: "failed to verify signature", + }) + + // Test 7: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Signature = "wrong signature" + + args = append(args, input{ + name: "Test 7", + message: msg, + contains: "failed to decode signature", + }) + + // Test 8: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Sender = "wrong sender" + + args = append(args, input{ + name: "Test 8", + message: msg, + contains: "failed to decode public key", + }) + + // Test 9: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = "wrong data" + + args = append(args, input{ + name: "Test 9", + message: msg, + contains: "failed to decode data", + }) + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + errAnswer := HandleMessage(arg.channel, arg.message, false) + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + }) + } + +} diff --git a/be1-go/internal/handler/publish.go b/be1-go/internal/handler/publish.go index 885f5ad6da..d9235d0ea8 100644 --- a/be1-go/internal/handler/publish.go +++ b/be1-go/internal/handler/publish.go @@ -22,7 +22,7 @@ func handlePublish(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handlePublish") } - errAnswer := handleChannel(publish.Params.Channel, publish.Params.Message, false) + errAnswer := HandleMessage(publish.Params.Channel, publish.Params.Message, false) if errAnswer != nil { return &publish.ID, errAnswer.Wrap("handlePublish") } diff --git a/be1-go/internal/handler/query.go b/be1-go/internal/handler/query.go index 7dee00444c..bca0b63265 100644 --- a/be1-go/internal/handler/query.go +++ b/be1-go/internal/handler/query.go @@ -12,12 +12,12 @@ import ( state2 "popstellar/internal/singleton/state" ) -func handleQuery(socket socket.Socket, msg []byte) *answer.Error { +func HandleQuery(socket socket.Socket, msg []byte) *answer.Error { var queryBase query.Base err := json.Unmarshal(msg, &queryBase) if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("handleQuery") + errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("HandleQuery") socket.SendError(nil, errAnswer) return errAnswer } @@ -47,7 +47,7 @@ func handleQuery(socket socket.Socket, msg []byte) *answer.Error { } if errAnswer != nil && queryBase.Method != query.MethodGreetServer && queryBase.Method != query.MethodHeartbeat { - errAnswer = errAnswer.Wrap("handleQuery") + errAnswer = errAnswer.Wrap("HandleQuery") socket.SendError(id, errAnswer) return errAnswer } diff --git a/be1-go/internal/handler/query_test.go b/be1-go/internal/handler/query_test.go index c8c2c88b10..ce48d98bfa 100644 --- a/be1-go/internal/handler/query_test.go +++ b/be1-go/internal/handler/query_test.go @@ -40,7 +40,7 @@ func Test_handleQuery(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { fakeSocket := mocks.FakeSocket{Id: "fakesocket"} - errAnswer := handleQuery(&fakeSocket, arg.message) + errAnswer := HandleQuery(&fakeSocket, arg.message) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/rumor.go b/be1-go/internal/handler/rumor.go index 39a1881757..6feef8d568 100644 --- a/be1-go/internal/handler/rumor.go +++ b/be1-go/internal/handler/rumor.go @@ -92,7 +92,7 @@ func tryHandlingMessages(channel string, unprocessedMsgs []message.Message) ([]m for i := 0; i < maxRetry; i++ { nbProcessed := 0 for index, msg := range unprocessedMsgs { - errAnswer := handleChannel(channel, msg, true) + errAnswer := HandleMessage(channel, msg, true) if errAnswer == nil { unprocessedMsgs = removeMessage(index-nbProcessed, unprocessedMsgs) processedMsgs = append(processedMsgs, msg.MessageID) From e1f781885aa5067db317d81892a8abd0fc5bc702 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 16:17:33 +0200 Subject: [PATCH 06/19] Revert "create a new file for the mid level check" This reverts commit ad0e85649b7684d18c1026a06de54eed42d76157. --- be1-go/internal/handler/answer.go | 10 +- be1-go/internal/handler/channel.go | 60 ++++++++- be1-go/internal/handler/channel_test.go | 105 ++++++++++++++- be1-go/internal/handler/incoming_message.go | 4 +- be1-go/internal/handler/message.go | 72 ---------- be1-go/internal/handler/message_test.go | 142 -------------------- be1-go/internal/handler/publish.go | 2 +- be1-go/internal/handler/query.go | 6 +- be1-go/internal/handler/query_test.go | 2 +- be1-go/internal/handler/rumor.go | 2 +- 10 files changed, 173 insertions(+), 232 deletions(-) delete mode 100644 be1-go/internal/handler/message.go delete mode 100644 be1-go/internal/handler/message_test.go diff --git a/be1-go/internal/handler/answer.go b/be1-go/internal/handler/answer.go index 3f919891a8..ca7346a387 100644 --- a/be1-go/internal/handler/answer.go +++ b/be1-go/internal/handler/answer.go @@ -15,13 +15,13 @@ const ( continueMongering = 0.5 ) -func HandleAnswer(msg []byte) *answer.Error { +func handleAnswer(msg []byte) *answer.Error { var answerMsg answer.Answer err := json.Unmarshal(msg, &answerMsg) if err != nil { errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return errAnswer.Wrap("HandleAnswer") + return errAnswer.Wrap("handleAnswer") } isRumor, errAnswer := state.IsRumorQuery(*answerMsg.ID) @@ -46,12 +46,12 @@ func HandleAnswer(msg []byte) *answer.Error { errAnswer = state.SetQueryReceived(*answerMsg.ID) if errAnswer != nil { - return errAnswer.Wrap("HandleAnswer") + return errAnswer.Wrap("handleAnswer") } errAnswer = handleGetMessagesByIDAnswer(answerMsg) if errAnswer != nil { - return errAnswer.Wrap("HandleAnswer") + return errAnswer.Wrap("handleAnswer") } return nil @@ -144,7 +144,7 @@ func tryToHandleMessages(msgsByChannel map[string]map[string]message.Message, so for _, channelID := range sortedChannelIDs { msgs := msgsByChannel[channelID] for msgID, msg := range msgs { - errAnswer := HandleMessage(channelID, msg, false) + errAnswer := handleChannel(channelID, msg, false) if errAnswer == nil { delete(msgsByChannel[channelID], msgID) continue diff --git a/be1-go/internal/handler/channel.go b/be1-go/internal/handler/channel.go index 3105f64839..062643495c 100644 --- a/be1-go/internal/handler/channel.go +++ b/be1-go/internal/handler/channel.go @@ -20,16 +20,34 @@ import ( "popstellar/internal/validation" ) -func HandleChannel(channelPath string, msg message.Message) *answer.Error { +func handleChannel(channelPath string, msg message.Message, fromRumor bool) *answer.Error { + errAnswer := verifyMessage(msg) + if errAnswer != nil { + return errAnswer.Wrap("handleChannel") + } + db, errAnswer := database.GetChannelRepositoryInstance() if errAnswer != nil { - return errAnswer.Wrap("HandleChannel") + return errAnswer.Wrap("handleChannel") + } + + msgAlreadyExists, err := db.HasMessage(msg.MessageID) + if err != nil { + errAnswer := answer.NewQueryDatabaseError("if message exists: %v", err) + return errAnswer.Wrap("handleChannel") + } + if msgAlreadyExists && fromRumor { + return nil + } + if msgAlreadyExists { + errAnswer := answer.NewInvalidActionError("message %s was already received", msg.MessageID) + return errAnswer.Wrap("handleChannel") } channelType, err := db.GetChannelType(channelPath) if err != nil { errAnswer := answer.NewQueryDatabaseError("channel type: %v", err) - return errAnswer.Wrap("HandleChannel") + return errAnswer.Wrap("handleChannel") } switch channelType { @@ -52,7 +70,7 @@ func HandleChannel(channelPath string, msg message.Message) *answer.Error { } if errAnswer != nil { - return errAnswer.Wrap("HandleChannel") + return errAnswer.Wrap("handleChannel") } return nil @@ -60,6 +78,40 @@ func HandleChannel(channelPath string, msg message.Message) *answer.Error { // util for the channels +func verifyMessage(msg message.Message) *answer.Error { + dataBytes, err := base64.URLEncoding.DecodeString(msg.Data) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode data: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + publicKeySender, err := base64.URLEncoding.DecodeString(msg.Sender) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode public key: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + signatureBytes, err := base64.URLEncoding.DecodeString(msg.Signature) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to decode signature: %v", err) + return errAnswer.Wrap("verifyMessage") + } + + err = schnorr.VerifyWithChecks(crypto.Suite, publicKeySender, dataBytes, signatureBytes) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to verify signature : %v", err) + return errAnswer.Wrap("verifyMessage") + } + + expectedMessageID := messagedata.Hash(msg.Data, msg.Signature) + if expectedMessageID != msg.MessageID { + errAnswer := answer.NewInvalidActionError("messageID is wrong: expected %s found %s", + expectedMessageID, msg.MessageID) + return errAnswer.Wrap("verifyMessage") + } + return nil +} + func verifyDataAndGetObjectAction(msg message.Message) (string, string, *answer.Error) { jsonData, err := base64.URLEncoding.DecodeString(msg.Data) if err != nil { diff --git a/be1-go/internal/handler/channel_test.go b/be1-go/internal/handler/channel_test.go index 452c0e841d..7e4df3eeda 100644 --- a/be1-go/internal/handler/channel_test.go +++ b/be1-go/internal/handler/channel_test.go @@ -64,9 +64,112 @@ func Test_handleChannel(t *testing.T) { contains: "DB is disconnected", }) + // Test 3: failed to handled message because message already exists + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + + mockRepository.On("HasMessage", msg.MessageID).Return(true, nil) + + args = append(args, input{ + name: "Test 3", + message: msg, + contains: "message " + msg.MessageID + " was already received", + }) + + // Test 4: failed to handled message because db is disconnected when querying if the message already exists + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + + mockRepository.On("HasMessage", msg.MessageID). + Return(false, xerrors.Errorf("DB is disconnected")) + + args = append(args, input{ + name: "Test 4", + message: msg, + contains: "DB is disconnected", + }) + + // Test 5: failed to handled message because the format of messageID + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + expectedMsgID := msg.MessageID + msg.MessageID = base64.URLEncoding.EncodeToString([]byte("wrong messageID")) + + args = append(args, input{ + name: "Test 5", + message: msg, + contains: "messageID is wrong: expected " + expectedMsgID + " found " + msg.MessageID, + }) + + // Test 6: failed to handled message because wrong sender + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Sender = base64.URLEncoding.EncodeToString([]byte("wrong sender")) + + args = append(args, input{ + name: "Test 6", + message: msg, + contains: "failed to verify signature", + }) + + // Test 7: failed to handled message because wrong data + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong data")) + + args = append(args, input{ + name: "Test 7", + message: msg, + contains: "failed to verify signature", + }) + + // Test 8: failed to handled message because wrong signature + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong signature")) + + args = append(args, input{ + name: "Test 8", + message: msg, + contains: "failed to verify signature", + }) + + // Test 9: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Signature = "wrong signature" + + args = append(args, input{ + name: "Test 9", + message: msg, + contains: "failed to decode signature", + }) + + // Test 10: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Sender = "wrong sender" + + args = append(args, input{ + name: "Test 10", + message: msg, + contains: "failed to decode public key", + }) + + // Test 11: failed to handled message because wrong signature encoding + + msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) + msg.Data = "wrong data" + + args = append(args, input{ + name: "Test 11", + message: msg, + contains: "failed to decode data", + }) + for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := HandleMessage(arg.channel, arg.message, false) + errAnswer := handleChannel(arg.channel, arg.message, false) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/incoming_message.go b/be1-go/internal/handler/incoming_message.go index 52024607e1..1b9d048e46 100644 --- a/be1-go/internal/handler/incoming_message.go +++ b/be1-go/internal/handler/incoming_message.go @@ -25,9 +25,9 @@ func HandleIncomingMessage(socket socket.Socket, msg []byte) error { switch rpcType { case message.RPCTypeQuery: - errAnswer = HandleQuery(socket, msg) + errAnswer = handleQuery(socket, msg) case message.RPCTypeAnswer: - errAnswer = HandleAnswer(msg) + errAnswer = handleAnswer(msg) default: errAnswer = answer.NewInvalidMessageFieldError("jsonRPC is of unknown type") } diff --git a/be1-go/internal/handler/message.go b/be1-go/internal/handler/message.go deleted file mode 100644 index 3e17213f78..0000000000 --- a/be1-go/internal/handler/message.go +++ /dev/null @@ -1,72 +0,0 @@ -package handler - -import ( - "encoding/base64" - "go.dedis.ch/kyber/v3/sign/schnorr" - "popstellar/internal/crypto" - "popstellar/internal/message/answer" - "popstellar/internal/message/messagedata" - "popstellar/internal/message/query/method/message" - "popstellar/internal/singleton/database" -) - -func HandleMessage(channelPath string, msg message.Message, fromRumor bool) *answer.Error { - errAnswer := verifyMessage(msg) - if errAnswer != nil { - return errAnswer.Wrap("HandleMessage") - } - - db, errAnswer := database.GetChannelRepositoryInstance() - if errAnswer != nil { - return errAnswer.Wrap("HandleMessage") - } - - msgAlreadyExists, err := db.HasMessage(msg.MessageID) - if err != nil { - errAnswer := answer.NewQueryDatabaseError("if message exists: %v", err) - return errAnswer.Wrap("HandleMessage") - } - if msgAlreadyExists && fromRumor { - return nil - } - if msgAlreadyExists { - errAnswer := answer.NewInvalidActionError("message %s was already received", msg.MessageID) - return errAnswer.Wrap("HandleMessage") - } - - return HandleChannel(channelPath, msg) -} - -func verifyMessage(msg message.Message) *answer.Error { - dataBytes, err := base64.URLEncoding.DecodeString(msg.Data) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode data: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - publicKeySender, err := base64.URLEncoding.DecodeString(msg.Sender) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode public key: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - signatureBytes, err := base64.URLEncoding.DecodeString(msg.Signature) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to decode signature: %v", err) - return errAnswer.Wrap("verifyMessage") - } - - err = schnorr.VerifyWithChecks(crypto.Suite, publicKeySender, dataBytes, signatureBytes) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to verify signature : %v", err) - return errAnswer.Wrap("verifyMessage") - } - - expectedMessageID := messagedata.Hash(msg.Data, msg.Signature) - if expectedMessageID != msg.MessageID { - errAnswer := answer.NewInvalidActionError("messageID is wrong: expected %s found %s", - expectedMessageID, msg.MessageID) - return errAnswer.Wrap("verifyMessage") - } - return nil -} diff --git a/be1-go/internal/handler/message_test.go b/be1-go/internal/handler/message_test.go deleted file mode 100644 index 05596fc72f..0000000000 --- a/be1-go/internal/handler/message_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package handler - -import ( - "encoding/base64" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" - "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" - "popstellar/internal/singleton/database" - "testing" - "time" -) - -func Test_handleMessage(t *testing.T) { - mockRepository := mocks.NewRepository(t) - database.SetDatabase(mockRepository) - - keypair := GenerateKeyPair(t) - sender := base64.URLEncoding.EncodeToString(keypair.PublicBuf) - - type input struct { - name string - channel string - message message.Message - contains string - } - - args := make([]input, 0) - - // Test 1: failed to handled message because message already exists - - msg := generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - - mockRepository.On("HasMessage", msg.MessageID).Return(true, nil) - - args = append(args, input{ - name: "Test 1", - message: msg, - contains: "message " + msg.MessageID + " was already received", - }) - - // Test 2: failed to handled message because db is disconnected when querying if the message already exists - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - - mockRepository.On("HasMessage", msg.MessageID). - Return(false, xerrors.Errorf("DB is disconnected")) - - args = append(args, input{ - name: "Test 2", - message: msg, - contains: "DB is disconnected", - }) - - // Test 3: failed to handled message because the format of messageID - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - expectedMsgID := msg.MessageID - msg.MessageID = base64.URLEncoding.EncodeToString([]byte("wrong messageID")) - - args = append(args, input{ - name: "Test 3", - message: msg, - contains: "messageID is wrong: expected " + expectedMsgID + " found " + msg.MessageID, - }) - - // Test 4: failed to handled message because wrong sender - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Sender = base64.URLEncoding.EncodeToString([]byte("wrong sender")) - - args = append(args, input{ - name: "Test 4", - message: msg, - contains: "failed to verify signature", - }) - - // Test 5: failed to handled message because wrong data - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong data")) - - args = append(args, input{ - name: "Test 5", - message: msg, - contains: "failed to verify signature", - }) - - // Test 6: failed to handled message because wrong signature - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = base64.URLEncoding.EncodeToString([]byte("wrong signature")) - - args = append(args, input{ - name: "Test 6", - message: msg, - contains: "failed to verify signature", - }) - - // Test 7: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Signature = "wrong signature" - - args = append(args, input{ - name: "Test 7", - message: msg, - contains: "failed to decode signature", - }) - - // Test 8: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Sender = "wrong sender" - - args = append(args, input{ - name: "Test 8", - message: msg, - contains: "failed to decode public key", - }) - - // Test 9: failed to handled message because wrong signature encoding - - msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) - msg.Data = "wrong data" - - args = append(args, input{ - name: "Test 9", - message: msg, - contains: "failed to decode data", - }) - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - errAnswer := HandleMessage(arg.channel, arg.message, false) - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - }) - } - -} diff --git a/be1-go/internal/handler/publish.go b/be1-go/internal/handler/publish.go index d9235d0ea8..885f5ad6da 100644 --- a/be1-go/internal/handler/publish.go +++ b/be1-go/internal/handler/publish.go @@ -22,7 +22,7 @@ func handlePublish(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handlePublish") } - errAnswer := HandleMessage(publish.Params.Channel, publish.Params.Message, false) + errAnswer := handleChannel(publish.Params.Channel, publish.Params.Message, false) if errAnswer != nil { return &publish.ID, errAnswer.Wrap("handlePublish") } diff --git a/be1-go/internal/handler/query.go b/be1-go/internal/handler/query.go index bca0b63265..7dee00444c 100644 --- a/be1-go/internal/handler/query.go +++ b/be1-go/internal/handler/query.go @@ -12,12 +12,12 @@ import ( state2 "popstellar/internal/singleton/state" ) -func HandleQuery(socket socket.Socket, msg []byte) *answer.Error { +func handleQuery(socket socket.Socket, msg []byte) *answer.Error { var queryBase query.Base err := json.Unmarshal(msg, &queryBase) if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("HandleQuery") + errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("handleQuery") socket.SendError(nil, errAnswer) return errAnswer } @@ -47,7 +47,7 @@ func HandleQuery(socket socket.Socket, msg []byte) *answer.Error { } if errAnswer != nil && queryBase.Method != query.MethodGreetServer && queryBase.Method != query.MethodHeartbeat { - errAnswer = errAnswer.Wrap("HandleQuery") + errAnswer = errAnswer.Wrap("handleQuery") socket.SendError(id, errAnswer) return errAnswer } diff --git a/be1-go/internal/handler/query_test.go b/be1-go/internal/handler/query_test.go index ce48d98bfa..c8c2c88b10 100644 --- a/be1-go/internal/handler/query_test.go +++ b/be1-go/internal/handler/query_test.go @@ -40,7 +40,7 @@ func Test_handleQuery(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { fakeSocket := mocks.FakeSocket{Id: "fakesocket"} - errAnswer := HandleQuery(&fakeSocket, arg.message) + errAnswer := handleQuery(&fakeSocket, arg.message) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/rumor.go b/be1-go/internal/handler/rumor.go index 6feef8d568..39a1881757 100644 --- a/be1-go/internal/handler/rumor.go +++ b/be1-go/internal/handler/rumor.go @@ -92,7 +92,7 @@ func tryHandlingMessages(channel string, unprocessedMsgs []message.Message) ([]m for i := 0; i < maxRetry; i++ { nbProcessed := 0 for index, msg := range unprocessedMsgs { - errAnswer := HandleMessage(channel, msg, true) + errAnswer := handleChannel(channel, msg, true) if errAnswer == nil { unprocessedMsgs = removeMessage(index-nbProcessed, unprocessedMsgs) processedMsgs = append(processedMsgs, msg.MessageID) From 1f8357b43d43b369bc67fc2855e1e28a1d7bc064 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 16:36:11 +0200 Subject: [PATCH 07/19] separate handler in two package + separate query --- be1-go/internal/handler/{ => high}/channel.go | 16 +- .../handler/{ => high}/channel_test.go | 49 +- be1-go/internal/handler/{ => high}/chirp.go | 2 +- .../internal/handler/{ => high}/chirp_test.go | 2 +- be1-go/internal/handler/{ => high}/coin.go | 2 +- .../internal/handler/{ => high}/coin_test.go | 4 +- .../internal/handler/{ => high}/election.go | 2 +- .../handler/{ => high}/election_test.go | 2 +- .../internal/handler/{ => high}/federation.go | 2 +- .../handler/{ => high}/federation_test.go | 2 +- be1-go/internal/handler/{ => high}/lao.go | 2 +- .../internal/handler/{ => high}/lao_test.go | 2 +- .../internal/handler/{ => high}/reaction.go | 2 +- .../handler/{ => high}/reaction_test.go | 2 +- be1-go/internal/handler/{ => high}/root.go | 2 +- .../internal/handler/{ => high}/root_test.go | 2 +- be1-go/internal/handler/{ => low}/answer.go | 5 +- .../internal/handler/{ => low}/answer_test.go | 5 +- be1-go/internal/handler/low/catchup.go | 34 + be1-go/internal/handler/low/catchup_test.go | 95 +++ .../internal/handler/low/getmessagesbyid.go | 34 + .../handler/low/getmessagesbyid_test.go | 110 +++ be1-go/internal/handler/low/greetserver.go | 71 ++ .../internal/handler/low/greetserver_test.go | 100 +++ be1-go/internal/handler/low/heartbeat.go | 68 ++ be1-go/internal/handler/low/heartbeat_test.go | 146 ++++ .../handler/{ => low}/incoming_message.go | 2 +- .../{ => low}/incoming_message_test.go | 2 +- be1-go/internal/handler/{ => low}/publish.go | 5 +- be1-go/internal/handler/low/query.go | 51 ++ be1-go/internal/handler/low/query_test.go | 39 ++ be1-go/internal/handler/{ => low}/rumor.go | 5 +- be1-go/internal/handler/low/subscribe.go | 34 + be1-go/internal/handler/low/subscribe_test.go | 99 +++ be1-go/internal/handler/low/unsubscribe.go | 34 + .../internal/handler/low/unsubscribe_test.go | 122 ++++ be1-go/internal/handler/query.go | 269 -------- be1-go/internal/handler/query_test.go | 647 ------------------ be1-go/internal/hub/hub.go | 6 +- be1-go/internal/mocks/generator/keys.go | 27 + 40 files changed, 1129 insertions(+), 976 deletions(-) rename be1-go/internal/handler/{ => high}/channel.go (94%) rename be1-go/internal/handler/{ => high}/channel_test.go (88%) rename be1-go/internal/handler/{ => high}/chirp.go (99%) rename be1-go/internal/handler/{ => high}/chirp_test.go (99%) rename be1-go/internal/handler/{ => high}/coin.go (99%) rename be1-go/internal/handler/{ => high}/coin_test.go (98%) rename be1-go/internal/handler/{ => high}/election.go (99%) rename be1-go/internal/handler/{ => high}/election_test.go (99%) rename be1-go/internal/handler/{ => high}/federation.go (99%) rename be1-go/internal/handler/{ => high}/federation_test.go (99%) rename be1-go/internal/handler/{ => high}/lao.go (99%) rename be1-go/internal/handler/{ => high}/lao_test.go (99%) rename be1-go/internal/handler/{ => high}/reaction.go (99%) rename be1-go/internal/handler/{ => high}/reaction_test.go (99%) rename be1-go/internal/handler/{ => high}/root.go (99%) rename be1-go/internal/handler/{ => high}/root_test.go (99%) rename be1-go/internal/handler/{ => low}/answer.go (97%) rename be1-go/internal/handler/{ => low}/answer_test.go (97%) create mode 100644 be1-go/internal/handler/low/catchup.go create mode 100644 be1-go/internal/handler/low/catchup_test.go create mode 100644 be1-go/internal/handler/low/getmessagesbyid.go create mode 100644 be1-go/internal/handler/low/getmessagesbyid_test.go create mode 100644 be1-go/internal/handler/low/greetserver.go create mode 100644 be1-go/internal/handler/low/greetserver_test.go create mode 100644 be1-go/internal/handler/low/heartbeat.go create mode 100644 be1-go/internal/handler/low/heartbeat_test.go rename be1-go/internal/handler/{ => low}/incoming_message.go (98%) rename be1-go/internal/handler/{ => low}/incoming_message_test.go (98%) rename be1-go/internal/handler/{ => low}/publish.go (91%) create mode 100644 be1-go/internal/handler/low/query.go create mode 100644 be1-go/internal/handler/low/query_test.go rename be1-go/internal/handler/{ => low}/rumor.go (97%) create mode 100644 be1-go/internal/handler/low/subscribe.go create mode 100644 be1-go/internal/handler/low/subscribe_test.go create mode 100644 be1-go/internal/handler/low/unsubscribe.go create mode 100644 be1-go/internal/handler/low/unsubscribe_test.go delete mode 100644 be1-go/internal/handler/query.go delete mode 100644 be1-go/internal/handler/query_test.go create mode 100644 be1-go/internal/mocks/generator/keys.go diff --git a/be1-go/internal/handler/channel.go b/be1-go/internal/handler/high/channel.go similarity index 94% rename from be1-go/internal/handler/channel.go rename to be1-go/internal/handler/high/channel.go index 062643495c..52f9ee2cd6 100644 --- a/be1-go/internal/handler/channel.go +++ b/be1-go/internal/handler/high/channel.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" @@ -20,34 +20,34 @@ import ( "popstellar/internal/validation" ) -func handleChannel(channelPath string, msg message.Message, fromRumor bool) *answer.Error { +func HandleChannel(channelPath string, msg message.Message, fromRumor bool) *answer.Error { errAnswer := verifyMessage(msg) if errAnswer != nil { - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } db, errAnswer := database.GetChannelRepositoryInstance() if errAnswer != nil { - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } msgAlreadyExists, err := db.HasMessage(msg.MessageID) if err != nil { errAnswer := answer.NewQueryDatabaseError("if message exists: %v", err) - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } if msgAlreadyExists && fromRumor { return nil } if msgAlreadyExists { errAnswer := answer.NewInvalidActionError("message %s was already received", msg.MessageID) - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } channelType, err := db.GetChannelType(channelPath) if err != nil { errAnswer := answer.NewQueryDatabaseError("channel type: %v", err) - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } switch channelType { @@ -70,7 +70,7 @@ func handleChannel(channelPath string, msg message.Message, fromRumor bool) *ans } if errAnswer != nil { - return errAnswer.Wrap("handleChannel") + return errAnswer.Wrap("HandleChannel") } return nil diff --git a/be1-go/internal/handler/channel_test.go b/be1-go/internal/handler/high/channel_test.go similarity index 88% rename from be1-go/internal/handler/channel_test.go rename to be1-go/internal/handler/high/channel_test.go index 7e4df3eeda..ee24fce3a4 100644 --- a/be1-go/internal/handler/channel_test.go +++ b/be1-go/internal/handler/high/channel_test.go @@ -1,15 +1,19 @@ -package handler +package high import ( "encoding/base64" + "fmt" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" - "go.dedis.ch/kyber/v3" "golang.org/x/xerrors" - "popstellar/internal/crypto" + "io" + "os" "popstellar/internal/message/query/method/message" "popstellar/internal/mocks" "popstellar/internal/mocks/generator" "popstellar/internal/singleton/database" + "popstellar/internal/singleton/utils" + "popstellar/internal/validation" "testing" "time" ) @@ -17,11 +21,27 @@ import ( // the public key used in every lao_create json files in the test_data/root folder const ownerPubBuf64 = "3yPmdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sY=" +var noLog = zerolog.New(io.Discard) + +func TestMain(m *testing.M) { + schemaValidator, err := validation.NewSchemaValidator() + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + utils.InitUtils(&noLog, schemaValidator) + + exitVal := m.Run() + + os.Exit(exitVal) +} + func Test_handleChannel(t *testing.T) { mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) - keypair := GenerateKeyPair(t) + keypair := generator.GenerateKeyPair(t) sender := base64.URLEncoding.EncodeToString(keypair.PublicBuf) type input struct { @@ -169,29 +189,10 @@ func Test_handleChannel(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannel(arg.channel, arg.message, false) + errAnswer := HandleChannel(arg.channel, arg.message, false) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) } } - -type Keypair struct { - Public kyber.Point - PublicBuf []byte - Private kyber.Scalar - PrivateBuf []byte -} - -func GenerateKeyPair(t *testing.T) Keypair { - secret := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) - point := crypto.Suite.Point().Mul(secret, nil) - - publicBuf, err := point.MarshalBinary() - require.NoError(t, err) - privateBuf, err := secret.MarshalBinary() - require.NoError(t, err) - - return Keypair{point, publicBuf, secret, privateBuf} -} diff --git a/be1-go/internal/handler/chirp.go b/be1-go/internal/handler/high/chirp.go similarity index 99% rename from be1-go/internal/handler/chirp.go rename to be1-go/internal/handler/high/chirp.go index f7ec1f4958..c5ebaafb63 100644 --- a/be1-go/internal/handler/chirp.go +++ b/be1-go/internal/handler/high/chirp.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/chirp_test.go b/be1-go/internal/handler/high/chirp_test.go similarity index 99% rename from be1-go/internal/handler/chirp_test.go rename to be1-go/internal/handler/high/chirp_test.go index dbba93c278..2dc7e52677 100644 --- a/be1-go/internal/handler/chirp_test.go +++ b/be1-go/internal/handler/high/chirp_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/coin.go b/be1-go/internal/handler/high/coin.go similarity index 99% rename from be1-go/internal/handler/coin.go rename to be1-go/internal/handler/high/coin.go index 3245d3ac3f..b80f791336 100644 --- a/be1-go/internal/handler/coin.go +++ b/be1-go/internal/handler/high/coin.go @@ -1,4 +1,4 @@ -package handler +package high import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/handler/coin_test.go b/be1-go/internal/handler/high/coin_test.go similarity index 98% rename from be1-go/internal/handler/coin_test.go rename to be1-go/internal/handler/high/coin_test.go index 27bf8c65e1..243728460e 100644 --- a/be1-go/internal/handler/coin_test.go +++ b/be1-go/internal/handler/high/coin_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" @@ -16,7 +16,7 @@ import ( "testing" ) -const coinPath string = "../validation/protocol/examples/messageData/coin" +const coinPath string = "../../validation/protocol/examples/messageData/coin" type inputTestHandleChannelCoin struct { name string diff --git a/be1-go/internal/handler/election.go b/be1-go/internal/handler/high/election.go similarity index 99% rename from be1-go/internal/handler/election.go rename to be1-go/internal/handler/high/election.go index 6dc0a8dc14..38d6da76b0 100644 --- a/be1-go/internal/handler/election.go +++ b/be1-go/internal/handler/high/election.go @@ -1,4 +1,4 @@ -package handler +package high import ( "bytes" diff --git a/be1-go/internal/handler/election_test.go b/be1-go/internal/handler/high/election_test.go similarity index 99% rename from be1-go/internal/handler/election_test.go rename to be1-go/internal/handler/high/election_test.go index b3a7edcc8a..1cf80cfcfb 100644 --- a/be1-go/internal/handler/election_test.go +++ b/be1-go/internal/handler/high/election_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/federation.go b/be1-go/internal/handler/high/federation.go similarity index 99% rename from be1-go/internal/handler/federation.go rename to be1-go/internal/handler/high/federation.go index fd96bd34a8..f4429e42b9 100644 --- a/be1-go/internal/handler/federation.go +++ b/be1-go/internal/handler/high/federation.go @@ -1,4 +1,4 @@ -package handler +package high import ( "crypto/rand" diff --git a/be1-go/internal/handler/federation_test.go b/be1-go/internal/handler/high/federation_test.go similarity index 99% rename from be1-go/internal/handler/federation_test.go rename to be1-go/internal/handler/high/federation_test.go index 067ab463c4..56ef993bc1 100644 --- a/be1-go/internal/handler/federation_test.go +++ b/be1-go/internal/handler/high/federation_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "database/sql" diff --git a/be1-go/internal/handler/lao.go b/be1-go/internal/handler/high/lao.go similarity index 99% rename from be1-go/internal/handler/lao.go rename to be1-go/internal/handler/high/lao.go index 98fdaddf3d..25583accda 100644 --- a/be1-go/internal/handler/lao.go +++ b/be1-go/internal/handler/high/lao.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/lao_test.go b/be1-go/internal/handler/high/lao_test.go similarity index 99% rename from be1-go/internal/handler/lao_test.go rename to be1-go/internal/handler/high/lao_test.go index bdfec2a09c..d1bc8949d6 100644 --- a/be1-go/internal/handler/lao_test.go +++ b/be1-go/internal/handler/high/lao_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/reaction.go b/be1-go/internal/handler/high/reaction.go similarity index 99% rename from be1-go/internal/handler/reaction.go rename to be1-go/internal/handler/high/reaction.go index 036e385b44..adeb5e8127 100644 --- a/be1-go/internal/handler/reaction.go +++ b/be1-go/internal/handler/high/reaction.go @@ -1,4 +1,4 @@ -package handler +package high import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/handler/reaction_test.go b/be1-go/internal/handler/high/reaction_test.go similarity index 99% rename from be1-go/internal/handler/reaction_test.go rename to be1-go/internal/handler/high/reaction_test.go index f0b1d2b402..0649f8f6f4 100644 --- a/be1-go/internal/handler/reaction_test.go +++ b/be1-go/internal/handler/high/reaction_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/root.go b/be1-go/internal/handler/high/root.go similarity index 99% rename from be1-go/internal/handler/root.go rename to be1-go/internal/handler/high/root.go index 1b84eec8e2..907670dbe5 100644 --- a/be1-go/internal/handler/root.go +++ b/be1-go/internal/handler/high/root.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/root_test.go b/be1-go/internal/handler/high/root_test.go similarity index 99% rename from be1-go/internal/handler/root_test.go rename to be1-go/internal/handler/high/root_test.go index 1d269a3ff1..d46379a4e9 100644 --- a/be1-go/internal/handler/root_test.go +++ b/be1-go/internal/handler/high/root_test.go @@ -1,4 +1,4 @@ -package handler +package high import ( "encoding/base64" diff --git a/be1-go/internal/handler/answer.go b/be1-go/internal/handler/low/answer.go similarity index 97% rename from be1-go/internal/handler/answer.go rename to be1-go/internal/handler/low/answer.go index ca7346a387..afbcb5d897 100644 --- a/be1-go/internal/handler/answer.go +++ b/be1-go/internal/handler/low/answer.go @@ -1,8 +1,9 @@ -package handler +package low import ( "encoding/json" "math/rand" + "popstellar/internal/handler/high" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method/message" @@ -144,7 +145,7 @@ func tryToHandleMessages(msgsByChannel map[string]map[string]message.Message, so for _, channelID := range sortedChannelIDs { msgs := msgsByChannel[channelID] for msgID, msg := range msgs { - errAnswer := handleChannel(channelID, msg, false) + errAnswer := high.HandleChannel(channelID, msg, false) if errAnswer == nil { delete(msgsByChannel[channelID], msgID) continue diff --git a/be1-go/internal/handler/answer_test.go b/be1-go/internal/handler/low/answer_test.go similarity index 97% rename from be1-go/internal/handler/answer_test.go rename to be1-go/internal/handler/low/answer_test.go index 7026b7cdad..c1dbdf2f31 100644 --- a/be1-go/internal/handler/answer_test.go +++ b/be1-go/internal/handler/low/answer_test.go @@ -1,4 +1,4 @@ -package handler +package low import ( "encoding/base64" @@ -10,6 +10,7 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" "popstellar/internal/singleton/database" "testing" "time" @@ -25,7 +26,7 @@ func Test_handleMessagesByChannel(t *testing.T) { expected map[string]map[string]message.Message } - keypair := GenerateKeyPair(t) + keypair := generator.GenerateKeyPair(t) now := time.Now().Unix() name := "LAO X" diff --git a/be1-go/internal/handler/low/catchup.go b/be1-go/internal/handler/low/catchup.go new file mode 100644 index 0000000000..1c36c1a708 --- /dev/null +++ b/be1-go/internal/handler/low/catchup.go @@ -0,0 +1,34 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" +) + +func handleCatchUp(socket socket.Socket, msg []byte) (*int, *answer.Error) { + var catchup method.Catchup + + err := json.Unmarshal(msg, &catchup) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return nil, errAnswer.Wrap("handleCatchUp") + } + + db, errAnswer := database.GetQueryRepositoryInstance() + if errAnswer != nil { + return &catchup.ID, errAnswer.Wrap("handleCatchUp") + } + + result, err := db.GetAllMessagesFromChannel(catchup.Params.Channel) + if err != nil { + errAnswer := answer.NewQueryDatabaseError("all message from channel %s: %v", catchup.Params.Channel, err) + return &catchup.ID, errAnswer.Wrap("handleCatchUp") + } + + socket.SendResult(catchup.ID, result, nil) + + return &catchup.ID, nil +} diff --git a/be1-go/internal/handler/low/catchup_test.go b/be1-go/internal/handler/low/catchup_test.go new file mode 100644 index 0000000000..43da69bc62 --- /dev/null +++ b/be1-go/internal/handler/low/catchup_test.go @@ -0,0 +1,95 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "golang.org/x/xerrors" + "popstellar/internal/message/query/method/message" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleCatchUp(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + mockRepository := mocks.NewRepository(t) + database.SetDatabase(mockRepository) + + type input struct { + name string + socket mocks.FakeSocket + ID int + message []byte + expected []message.Message + isError bool + contains string + } + + args := make([]input, 0) + + // Test 1: successfully catchup 4 messages on a channel + + fakeSocket := mocks.FakeSocket{Id: "1"} + ID := 1 + channel := "/root/lao1" + messagesToCatchUp := []message.Message{ + generator.NewNothingMsg(t, "sender1", nil), + generator.NewNothingMsg(t, "sender2", nil), + generator.NewNothingMsg(t, "sender3", nil), + generator.NewNothingMsg(t, "sender4", nil), + } + + mockRepository.On("GetAllMessagesFromChannel", channel).Return(messagesToCatchUp, nil) + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + ID: ID, + message: generator.NewCatchupQuery(t, ID, channel), + expected: messagesToCatchUp, + isError: false, + }) + + // Test 2: failed to catchup because DB is disconnected + + fakeSocket = mocks.FakeSocket{Id: "2"} + ID = 2 + channel = "/root/lao2" + + mockRepository.On("GetAllMessagesFromChannel", channel). + Return(nil, xerrors.Errorf("DB is disconnected")) + + args = append(args, input{ + name: "Test 2", + socket: fakeSocket, + ID: ID, + message: generator.NewCatchupQuery(t, ID, channel), + isError: true, + contains: "DB is disconnected", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + id, errAnswer := handleCatchUp(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + require.NotNil(t, id) + require.Equal(t, arg.ID, *id) + } else { + require.Nil(t, errAnswer) + require.Equal(t, arg.expected, arg.socket.Res) + } + }) + } +} diff --git a/be1-go/internal/handler/low/getmessagesbyid.go b/be1-go/internal/handler/low/getmessagesbyid.go new file mode 100644 index 0000000000..537954ddfc --- /dev/null +++ b/be1-go/internal/handler/low/getmessagesbyid.go @@ -0,0 +1,34 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" +) + +func handleGetMessagesByID(socket socket.Socket, msg []byte) (*int, *answer.Error) { + var getMessagesById method.GetMessagesById + + err := json.Unmarshal(msg, &getMessagesById) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return nil, errAnswer.Wrap("handleGetMessageByID") + } + + db, errAnswer := database.GetQueryRepositoryInstance() + if errAnswer != nil { + return &getMessagesById.ID, errAnswer.Wrap("handleGetMessageByID") + } + + result, err := db.GetResultForGetMessagesByID(getMessagesById.Params) + if err != nil { + errAnswer := answer.NewQueryDatabaseError("result for get messages by id: %v", err) + return &getMessagesById.ID, errAnswer.Wrap("handleGetMessageByID") + } + + socket.SendResult(getMessagesById.ID, nil, result) + + return &getMessagesById.ID, nil +} diff --git a/be1-go/internal/handler/low/getmessagesbyid_test.go b/be1-go/internal/handler/low/getmessagesbyid_test.go new file mode 100644 index 0000000000..ee312cc794 --- /dev/null +++ b/be1-go/internal/handler/low/getmessagesbyid_test.go @@ -0,0 +1,110 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "golang.org/x/xerrors" + "popstellar/internal/message/query/method/message" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleGetMessagesByID(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + mockRepository := mocks.NewRepository(t) + database.SetDatabase(mockRepository) + + type input struct { + name string + socket mocks.FakeSocket + ID int + message []byte + expected map[string][]message.Message + isError bool + contains string + } + + args := make([]input, 0) + + // Test 1: successfully handled getMessagesByID and sent the result + + fakeSocket := mocks.FakeSocket{Id: "1"} + ID := 1 + + expected1 := make(map[string][]message.Message) + expected1["/root"] = []message.Message{ + generator.NewNothingMsg(t, "sender1", nil), + generator.NewNothingMsg(t, "sender2", nil), + generator.NewNothingMsg(t, "sender3", nil), + generator.NewNothingMsg(t, "sender4", nil), + } + expected1["/root/lao1"] = []message.Message{ + generator.NewNothingMsg(t, "sender5", nil), + generator.NewNothingMsg(t, "sender6", nil), + } + + paramsGetMessagesByID1 := make(map[string][]string) + for k, v := range expected1 { + paramsGetMessagesByID1[k] = make([]string, 0) + for _, w := range v { + paramsGetMessagesByID1[k] = append(paramsGetMessagesByID1[k], w.MessageID) + } + } + + mockRepository.On("GetResultForGetMessagesByID", paramsGetMessagesByID1).Return(expected1, nil) + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + ID: ID, + message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), + expected: expected1, + isError: false, + }) + + // Test 2: failed to handled getMessagesByID because DB is disconnected + + fakeSocket = mocks.FakeSocket{Id: "2"} + ID = 2 + + paramsGetMessagesByID2 := make(map[string][]string) + + mockRepository.On("GetResultForGetMessagesByID", paramsGetMessagesByID2). + Return(nil, xerrors.Errorf("DB is disconnected")) + + args = append(args, input{ + name: "Test 2", + socket: fakeSocket, + ID: ID, + message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), + isError: true, + contains: "DB is disconnected", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + id, errAnswer := handleGetMessagesByID(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + require.NotNil(t, id) + require.Contains(t, errAnswer.Error(), arg.contains) + require.Equal(t, arg.ID, *id) + } else { + require.Nil(t, errAnswer) + require.NotNil(t, arg.expected) + require.Equal(t, arg.expected, arg.socket.MissingMsgs) + } + }) + } +} diff --git a/be1-go/internal/handler/low/greetserver.go b/be1-go/internal/handler/low/greetserver.go new file mode 100644 index 0000000000..d70371f201 --- /dev/null +++ b/be1-go/internal/handler/low/greetserver.go @@ -0,0 +1,71 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/state" +) + +func handleGreetServer(socket socket.Socket, byteMessage []byte) (*int, *answer.Error) { + var greetServer method.GreetServer + + err := json.Unmarshal(byteMessage, &greetServer) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return nil, errAnswer.Wrap("handleGreetServer") + } + + errAnswer := state.AddPeerInfo(socket.ID(), greetServer.Params) + if errAnswer != nil { + return nil, errAnswer.Wrap("handleGreetServer") + } + + isGreeted, errAnswer := state.IsPeerGreeted(socket.ID()) + if errAnswer != nil { + return nil, errAnswer.Wrap("handleGreetServer") + } + if isGreeted { + return nil, nil + } + + serverPublicKey, clientAddress, serverAddress, errAnswer := config.GetServerInfo() + if errAnswer != nil { + return nil, errAnswer.Wrap("handleGreetServer") + } + + greetServerParams := method.GreetServerParams{ + PublicKey: serverPublicKey, + ServerAddress: serverAddress, + ClientAddress: clientAddress, + } + + serverGreet := &method.GreetServer{ + Base: query.Base{ + JSONRPCBase: message.JSONRPCBase{ + JSONRPC: "2.0", + }, + Method: query.MethodGreetServer, + }, + Params: greetServerParams, + } + + buf, err := json.Marshal(serverGreet) + if err != nil { + errAnswer := answer.NewInternalServerError("failed to marshal: %v", err) + return nil, errAnswer.Wrap("handleGreetServer") + } + + socket.Send(buf) + + errAnswer = state.AddPeerGreeted(socket.ID()) + if errAnswer != nil { + return nil, errAnswer.Wrap("handleGreetServer") + } + + return nil, nil +} diff --git a/be1-go/internal/handler/low/greetserver_test.go b/be1-go/internal/handler/low/greetserver_test.go new file mode 100644 index 0000000000..b999cbbb33 --- /dev/null +++ b/be1-go/internal/handler/low/greetserver_test.go @@ -0,0 +1,100 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "popstellar/internal/crypto" + "popstellar/internal/message/query/method" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/config" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleGreetServer(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + serverSecretKey := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) + serverPublicKey := crypto.Suite.Point().Mul(serverSecretKey, nil) + + config.SetConfig(nil, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") + + type input struct { + name string + socket mocks.FakeSocket + message []byte + needGreet bool + isError bool + contains string + } + + args := make([]input, 0) + + greetServer := generator.NewGreetServerQuery(t, "pk", "client", "server") + + // Test 1: reply with greet server when receiving a greet server from a new server + + fakeSocket := mocks.FakeSocket{Id: "1"} + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + message: greetServer, + needGreet: true, + isError: false, + }) + + // Test 2: doesn't reply with greet server when already greeted the server + + fakeSocket = mocks.FakeSocket{Id: "2"} + + peers.AddPeerGreeted(fakeSocket.Id) + + args = append(args, input{ + name: "Test 2", + message: greetServer, + socket: fakeSocket, + needGreet: false, + isError: false, + }) + + // Test 3: return an error if the socket ID is already used by another server + + fakeSocket = mocks.FakeSocket{Id: "3"} + + err := peers.AddPeerInfo(fakeSocket.Id, method.GreetServerParams{}) + require.NoError(t, err) + + args = append(args, input{ + name: "Test 3", + socket: fakeSocket, + message: greetServer, + isError: true, + contains: "failed to add peer", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + id, errAnswer := handleGreetServer(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + require.Nil(t, id) + } else if arg.needGreet { + require.Nil(t, errAnswer) + require.NotNil(t, arg.socket.Msg) + } else { + require.Nil(t, errAnswer) + require.Nil(t, arg.socket.Msg) + } + }) + } +} diff --git a/be1-go/internal/handler/low/heartbeat.go b/be1-go/internal/handler/low/heartbeat.go new file mode 100644 index 0000000000..723564803a --- /dev/null +++ b/be1-go/internal/handler/low/heartbeat.go @@ -0,0 +1,68 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/message" + "popstellar/internal/message/answer" + "popstellar/internal/message/query" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" +) + +func handleHeartbeat(socket socket.Socket, byteMessage []byte) *answer.Error { + var heartbeat method.Heartbeat + + err := json.Unmarshal(byteMessage, &heartbeat) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return errAnswer.Wrap("handleHeartbeat") + } + + db, errAnswer := database.GetQueryRepositoryInstance() + if errAnswer != nil { + return errAnswer.Wrap("handleHeartbeat") + } + + result, err := db.GetParamsForGetMessageByID(heartbeat.Params) + if err != nil { + errAnswer := answer.NewQueryDatabaseError("params for get messages by id: %v", err) + return errAnswer.Wrap("handleHeartbeat") + } + + if len(result) == 0 { + return nil + } + + queryId, errAnswer := state.GetNextID() + if errAnswer != nil { + return errAnswer.Wrap("handleHeartbeat") + } + + getMessagesById := method.GetMessagesById{ + Base: query.Base{ + JSONRPCBase: message.JSONRPCBase{ + JSONRPC: "2.0", + }, + Method: query.MethodGetMessagesById, + }, + ID: queryId, + Params: result, + } + + buf, err := json.Marshal(getMessagesById) + if err != nil { + errAnswer := answer.NewInternalServerError("failed to marshal: %v", err) + return errAnswer.Wrap("handleHeartbeat") + } + + socket.Send(buf) + + errAnswer = state.AddQuery(queryId, getMessagesById) + if errAnswer != nil { + return errAnswer.Wrap("handleHeartbeat") + } + + return nil +} diff --git a/be1-go/internal/handler/low/heartbeat_test.go b/be1-go/internal/handler/low/heartbeat_test.go new file mode 100644 index 0000000000..5b516dcaac --- /dev/null +++ b/be1-go/internal/handler/low/heartbeat_test.go @@ -0,0 +1,146 @@ +package low + +import ( + "encoding/json" + "github.com/stretchr/testify/require" + "golang.org/x/xerrors" + "popstellar/internal/message/query/method" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/database" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleHeartbeat(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + mockRepository := mocks.NewRepository(t) + database.SetDatabase(mockRepository) + + type input struct { + name string + socket mocks.FakeSocket + message []byte + expected map[string][]string + isError bool + contains string + } + + msgIDs := []string{"msg0", "msg1", "msg2", "msg3", "msg4", "msg5", "msg6"} + + args := make([]input, 0) + + // Test 1: successfully handled heartbeat with some messages to catching up + + fakeSocket := mocks.FakeSocket{Id: "1"} + + heartbeatMsgIDs1 := make(map[string][]string) + heartbeatMsgIDs1["/root"] = []string{ + msgIDs[0], + msgIDs[1], + msgIDs[2], + } + heartbeatMsgIDs1["root/lao1"] = []string{ + msgIDs[3], + msgIDs[4], + } + heartbeatMsgIDs1["root/lao2"] = []string{ + msgIDs[5], + msgIDs[6], + } + + expected1 := make(map[string][]string) + expected1["/root"] = []string{ + msgIDs[1], + msgIDs[2], + } + expected1["root/lao1"] = []string{ + msgIDs[4], + } + + mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs1).Return(expected1, nil) + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs1), + expected: expected1, + isError: false, + }) + + // Test 2: successfully handled heartbeat with nothing to catching up + + fakeSocket = mocks.FakeSocket{Id: "2"} + + heartbeatMsgIDs2 := make(map[string][]string) + heartbeatMsgIDs2["/root"] = []string{ + msgIDs[0], + msgIDs[1], + msgIDs[2], + } + + mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs2).Return(nil, nil) + + args = append(args, input{ + name: "Test 2", + socket: fakeSocket, + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs2), + isError: false, + }) + + // Test 3: failed to handled heartbeat because DB is disconnected + + fakeSocket = mocks.FakeSocket{Id: "3"} + + heartbeatMsgIDs3 := make(map[string][]string) + heartbeatMsgIDs3["/root"] = []string{ + msgIDs[0], + msgIDs[1], + msgIDs[2], + } + heartbeatMsgIDs3["root/lao1"] = []string{ + msgIDs[3], + msgIDs[4], + } + + mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs3). + Return(nil, xerrors.Errorf("DB is disconnected")) + + args = append(args, input{ + name: "failed to popquery DB", + socket: fakeSocket, + message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs3), + isError: true, + contains: "DB is disconnected", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + errAnswer := handleHeartbeat(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + } else if arg.expected != nil { + require.Nil(t, errAnswer) + require.NotNil(t, arg.socket.Msg) + + var getMessageByID method.GetMessagesById + err := json.Unmarshal(arg.socket.Msg, &getMessageByID) + require.NoError(t, err) + + require.Equal(t, arg.expected, getMessageByID.Params) + } else { + require.Nil(t, errAnswer) + require.Nil(t, arg.socket.Msg) + } + }) + } +} diff --git a/be1-go/internal/handler/incoming_message.go b/be1-go/internal/handler/low/incoming_message.go similarity index 98% rename from be1-go/internal/handler/incoming_message.go rename to be1-go/internal/handler/low/incoming_message.go index 1b9d048e46..c22cc71ba0 100644 --- a/be1-go/internal/handler/incoming_message.go +++ b/be1-go/internal/handler/low/incoming_message.go @@ -1,4 +1,4 @@ -package handler +package low import ( "popstellar/internal/message" diff --git a/be1-go/internal/handler/incoming_message_test.go b/be1-go/internal/handler/low/incoming_message_test.go similarity index 98% rename from be1-go/internal/handler/incoming_message_test.go rename to be1-go/internal/handler/low/incoming_message_test.go index 99f4620011..4994054de4 100644 --- a/be1-go/internal/handler/incoming_message_test.go +++ b/be1-go/internal/handler/low/incoming_message_test.go @@ -1,4 +1,4 @@ -package handler +package low import ( "encoding/base64" diff --git a/be1-go/internal/handler/publish.go b/be1-go/internal/handler/low/publish.go similarity index 91% rename from be1-go/internal/handler/publish.go rename to be1-go/internal/handler/low/publish.go index 885f5ad6da..f50bbbfc64 100644 --- a/be1-go/internal/handler/publish.go +++ b/be1-go/internal/handler/low/publish.go @@ -1,7 +1,8 @@ -package handler +package low import ( "encoding/json" + "popstellar/internal/handler/high" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" @@ -22,7 +23,7 @@ func handlePublish(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handlePublish") } - errAnswer := handleChannel(publish.Params.Channel, publish.Params.Message, false) + errAnswer := high.HandleChannel(publish.Params.Channel, publish.Params.Message, false) if errAnswer != nil { return &publish.ID, errAnswer.Wrap("handlePublish") } diff --git a/be1-go/internal/handler/low/query.go b/be1-go/internal/handler/low/query.go new file mode 100644 index 0000000000..2f144a5793 --- /dev/null +++ b/be1-go/internal/handler/low/query.go @@ -0,0 +1,51 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/message/answer" + "popstellar/internal/message/query" + "popstellar/internal/network/socket" +) + +func handleQuery(socket socket.Socket, msg []byte) *answer.Error { + var queryBase query.Base + + err := json.Unmarshal(msg, &queryBase) + if err != nil { + errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("handleQuery") + socket.SendError(nil, errAnswer) + return errAnswer + } + + var id *int = nil + var errAnswer *answer.Error + + switch queryBase.Method { + case query.MethodCatchUp: + id, errAnswer = handleCatchUp(socket, msg) + case query.MethodGetMessagesById: + id, errAnswer = handleGetMessagesByID(socket, msg) + case query.MethodGreetServer: + id, errAnswer = handleGreetServer(socket, msg) + case query.MethodHeartbeat: + errAnswer = handleHeartbeat(socket, msg) + case query.MethodPublish: + id, errAnswer = handlePublish(socket, msg) + case query.MethodSubscribe: + id, errAnswer = handleSubscribe(socket, msg) + case query.MethodUnsubscribe: + id, errAnswer = handleUnsubscribe(socket, msg) + case query.MethodRumor: + id, errAnswer = handleRumor(socket, msg) + default: + errAnswer = answer.NewInvalidResourceError("unexpected method: '%s'", queryBase.Method) + } + + if errAnswer != nil && queryBase.Method != query.MethodGreetServer && queryBase.Method != query.MethodHeartbeat { + errAnswer = errAnswer.Wrap("handleQuery") + socket.SendError(id, errAnswer) + return errAnswer + } + + return nil +} diff --git a/be1-go/internal/handler/low/query_test.go b/be1-go/internal/handler/low/query_test.go new file mode 100644 index 0000000000..36ef3ce594 --- /dev/null +++ b/be1-go/internal/handler/low/query_test.go @@ -0,0 +1,39 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "testing" +) + +func Test_handleQuery(t *testing.T) { + type input struct { + name string + message []byte + contains string + } + + args := make([]input, 0) + + // Test 1: failed to handled popquery because unknown method + + msg := generator.NewNothingQuery(t, 999) + + args = append(args, input{ + name: "Test 1", + message: msg, + contains: "unexpected method", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + fakeSocket := mocks.FakeSocket{Id: "fakesocket"} + errAnswer := handleQuery(&fakeSocket, arg.message) + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + }) + } +} diff --git a/be1-go/internal/handler/rumor.go b/be1-go/internal/handler/low/rumor.go similarity index 97% rename from be1-go/internal/handler/rumor.go rename to be1-go/internal/handler/low/rumor.go index 39a1881757..f9fe9ab2e2 100644 --- a/be1-go/internal/handler/rumor.go +++ b/be1-go/internal/handler/low/rumor.go @@ -1,7 +1,8 @@ -package handler +package low import ( "encoding/json" + "popstellar/internal/handler/high" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" @@ -92,7 +93,7 @@ func tryHandlingMessages(channel string, unprocessedMsgs []message.Message) ([]m for i := 0; i < maxRetry; i++ { nbProcessed := 0 for index, msg := range unprocessedMsgs { - errAnswer := handleChannel(channel, msg, true) + errAnswer := high.HandleChannel(channel, msg, true) if errAnswer == nil { unprocessedMsgs = removeMessage(index-nbProcessed, unprocessedMsgs) processedMsgs = append(processedMsgs, msg.MessageID) diff --git a/be1-go/internal/handler/low/subscribe.go b/be1-go/internal/handler/low/subscribe.go new file mode 100644 index 0000000000..54fec00dac --- /dev/null +++ b/be1-go/internal/handler/low/subscribe.go @@ -0,0 +1,34 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/handler/high" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/state" +) + +func handleSubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { + var subscribe method.Subscribe + + err := json.Unmarshal(msg, &subscribe) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return nil, errAnswer.Wrap("handleSubscribe") + } + + if high.Root == subscribe.Params.Channel { + errAnswer := answer.NewInvalidActionError("cannot Subscribe to root channel") + return &subscribe.ID, errAnswer.Wrap("handleSubscribe") + } + + errAnswer := state.Subscribe(socket, subscribe.Params.Channel) + if errAnswer != nil { + return &subscribe.ID, errAnswer.Wrap("handleSubscribe") + } + + socket.SendResult(subscribe.ID, nil, nil) + + return &subscribe.ID, nil +} diff --git a/be1-go/internal/handler/low/subscribe_test.go b/be1-go/internal/handler/low/subscribe_test.go new file mode 100644 index 0000000000..84353723aa --- /dev/null +++ b/be1-go/internal/handler/low/subscribe_test.go @@ -0,0 +1,99 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleSubscribe(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + type input struct { + name string + socket mocks.FakeSocket + ID int + channel string + message []byte + isError bool + contains string + } + + args := make([]input, 0) + + // Test 1: successfully subscribe to a channel + + fakeSocket := mocks.FakeSocket{Id: "1"} + ID := 1 + channel := "/root/lao1" + + errAnswer := subs.AddChannel(channel) + require.Nil(t, errAnswer) + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewSubscribeQuery(t, ID, channel), + isError: false, + }) + + // Test 2: failed to subscribe to an unknown channel + + fakeSocket = mocks.FakeSocket{Id: "2"} + ID = 2 + channel = "/root/lao2" + + args = append(args, input{ + name: "Test 2", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewSubscribeQuery(t, ID, channel), + isError: true, + contains: "cannot Subscribe to unknown channel", + }) + + // cannot Subscribe to root + + fakeSocket = mocks.FakeSocket{Id: "3"} + ID = 3 + channel = "/root" + + args = append(args, input{ + name: "Test 3", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewSubscribeQuery(t, ID, channel), + isError: true, + contains: "cannot Subscribe to root channel", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + id, errAnswer := handleSubscribe(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + require.Equal(t, arg.ID, *id) + } else { + require.Nil(t, errAnswer) + isSubscribed, err := subs.IsSubscribed(arg.channel, &arg.socket) + require.NoError(t, err) + require.True(t, isSubscribed) + } + }) + } +} diff --git a/be1-go/internal/handler/low/unsubscribe.go b/be1-go/internal/handler/low/unsubscribe.go new file mode 100644 index 0000000000..c33fe3fe19 --- /dev/null +++ b/be1-go/internal/handler/low/unsubscribe.go @@ -0,0 +1,34 @@ +package low + +import ( + "encoding/json" + "popstellar/internal/handler/high" + "popstellar/internal/message/answer" + "popstellar/internal/message/query/method" + "popstellar/internal/network/socket" + "popstellar/internal/singleton/state" +) + +func handleUnsubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { + var unsubscribe method.Unsubscribe + + err := json.Unmarshal(msg, &unsubscribe) + if err != nil { + errAnswer := answer.NewJsonUnmarshalError(err.Error()) + return nil, errAnswer.Wrap("handleUnsubscribe") + } + + if high.Root == unsubscribe.Params.Channel { + errAnswer := answer.NewInvalidActionError("cannot Unsubscribe from root channel") + return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") + } + + errAnswer := state.Unsubscribe(socket, unsubscribe.Params.Channel) + if errAnswer != nil { + return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") + } + + socket.SendResult(unsubscribe.ID, nil, nil) + + return &unsubscribe.ID, nil +} diff --git a/be1-go/internal/handler/low/unsubscribe_test.go b/be1-go/internal/handler/low/unsubscribe_test.go new file mode 100644 index 0000000000..a5c99d7675 --- /dev/null +++ b/be1-go/internal/handler/low/unsubscribe_test.go @@ -0,0 +1,122 @@ +package low + +import ( + "github.com/stretchr/testify/require" + "popstellar/internal/mocks" + "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/state" + "popstellar/internal/types" + "testing" +) + +func Test_handleUnsubscribe(t *testing.T) { + subs := types.NewSubscribers() + queries := types.NewQueries(&noLog) + peers := types.NewPeers() + hubParams := types.NewHubParams() + + state.SetState(subs, peers, queries, hubParams) + + type input struct { + name string + socket mocks.FakeSocket + ID int + channel string + message []byte + isError bool + contains string + } + + args := make([]input, 0) + + // Test 1: successfully unsubscribe from a subscribed channel + + fakeSocket := mocks.FakeSocket{Id: "1"} + ID := 1 + channel := "/root/lao1" + + errAnswer := subs.AddChannel(channel) + require.Nil(t, errAnswer) + + errAnswer = subs.Subscribe(channel, &fakeSocket) + require.Nil(t, errAnswer) + + args = append(args, input{ + name: "Test 1", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewUnsubscribeQuery(t, ID, channel), + isError: false, + }) + + // Test 2: failed to unsubscribe because not subscribed to channel + + fakeSocket = mocks.FakeSocket{Id: "2"} + ID = 2 + channel = "/root/lao2" + + errAnswer = subs.AddChannel(channel) + require.Nil(t, errAnswer) + + args = append(args, input{ + name: "Test 2", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewUnsubscribeQuery(t, ID, channel), + isError: true, + contains: "cannot Unsubscribe from a channel not subscribed", + }) + + // Test 3: failed to unsubscribe because unknown channel + + fakeSocket = mocks.FakeSocket{Id: "3"} + ID = 3 + channel = "/root/lao3" + + args = append(args, input{ + name: "Test 3", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewUnsubscribeQuery(t, ID, channel), + isError: true, + contains: "cannot Unsubscribe from unknown channel", + }) + + // Test 3: failed to unsubscribe because cannot unsubscribe from root channel + + fakeSocket = mocks.FakeSocket{Id: "4"} + ID = 4 + channel = "/root" + + args = append(args, input{ + name: "Test 4", + socket: fakeSocket, + ID: ID, + channel: channel, + message: generator.NewUnsubscribeQuery(t, ID, channel), + isError: true, + contains: "cannot Unsubscribe from root channel", + }) + + // run all tests + + for _, arg := range args { + t.Run(arg.name, func(t *testing.T) { + id, errAnswer := handleUnsubscribe(&arg.socket, arg.message) + if arg.isError { + require.NotNil(t, errAnswer) + require.Contains(t, errAnswer.Error(), arg.contains) + require.Equal(t, arg.ID, *id) + } else { + require.Nil(t, errAnswer) + + isSubscribe, err := subs.IsSubscribed(arg.channel, &arg.socket) + require.NoError(t, err) + require.False(t, isSubscribe) + } + }) + } +} diff --git a/be1-go/internal/handler/query.go b/be1-go/internal/handler/query.go deleted file mode 100644 index 7dee00444c..0000000000 --- a/be1-go/internal/handler/query.go +++ /dev/null @@ -1,269 +0,0 @@ -package handler - -import ( - "encoding/json" - jsonrpc "popstellar/internal/message" - "popstellar/internal/message/answer" - "popstellar/internal/message/query" - "popstellar/internal/message/query/method" - "popstellar/internal/network/socket" - "popstellar/internal/singleton/config" - "popstellar/internal/singleton/database" - state2 "popstellar/internal/singleton/state" -) - -func handleQuery(socket socket.Socket, msg []byte) *answer.Error { - var queryBase query.Base - - err := json.Unmarshal(msg, &queryBase) - if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("handleQuery") - socket.SendError(nil, errAnswer) - return errAnswer - } - - var id *int = nil - var errAnswer *answer.Error - - switch queryBase.Method { - case query.MethodCatchUp: - id, errAnswer = handleCatchUp(socket, msg) - case query.MethodGetMessagesById: - id, errAnswer = handleGetMessagesByID(socket, msg) - case query.MethodGreetServer: - id, errAnswer = handleGreetServer(socket, msg) - case query.MethodHeartbeat: - errAnswer = handleHeartbeat(socket, msg) - case query.MethodPublish: - id, errAnswer = handlePublish(socket, msg) - case query.MethodSubscribe: - id, errAnswer = handleSubscribe(socket, msg) - case query.MethodUnsubscribe: - id, errAnswer = handleUnsubscribe(socket, msg) - case query.MethodRumor: - id, errAnswer = handleRumor(socket, msg) - default: - errAnswer = answer.NewInvalidResourceError("unexpected method: '%s'", queryBase.Method) - } - - if errAnswer != nil && queryBase.Method != query.MethodGreetServer && queryBase.Method != query.MethodHeartbeat { - errAnswer = errAnswer.Wrap("handleQuery") - socket.SendError(id, errAnswer) - return errAnswer - } - - return nil -} - -func handleGreetServer(socket socket.Socket, byteMessage []byte) (*int, *answer.Error) { - var greetServer method.GreetServer - - err := json.Unmarshal(byteMessage, &greetServer) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return nil, errAnswer.Wrap("handleGreetServer") - } - - errAnswer := state2.AddPeerInfo(socket.ID(), greetServer.Params) - if errAnswer != nil { - return nil, errAnswer.Wrap("handleGreetServer") - } - - isGreeted, errAnswer := state2.IsPeerGreeted(socket.ID()) - if errAnswer != nil { - return nil, errAnswer.Wrap("handleGreetServer") - } - if isGreeted { - return nil, nil - } - - serverPublicKey, clientAddress, serverAddress, errAnswer := config.GetServerInfo() - if errAnswer != nil { - return nil, errAnswer.Wrap("handleGreetServer") - } - - greetServerParams := method.GreetServerParams{ - PublicKey: serverPublicKey, - ServerAddress: serverAddress, - ClientAddress: clientAddress, - } - - serverGreet := &method.GreetServer{ - Base: query.Base{ - JSONRPCBase: jsonrpc.JSONRPCBase{ - JSONRPC: "2.0", - }, - Method: query.MethodGreetServer, - }, - Params: greetServerParams, - } - - buf, err := json.Marshal(serverGreet) - if err != nil { - errAnswer := answer.NewInternalServerError("failed to marshal: %v", err) - return nil, errAnswer.Wrap("handleGreetServer") - } - - socket.Send(buf) - - errAnswer = state2.AddPeerGreeted(socket.ID()) - if errAnswer != nil { - return nil, errAnswer.Wrap("handleGreetServer") - } - - return nil, nil -} - -func handleSubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { - var subscribe method.Subscribe - - err := json.Unmarshal(msg, &subscribe) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return nil, errAnswer.Wrap("handleSubscribe") - } - - if Root == subscribe.Params.Channel { - errAnswer := answer.NewInvalidActionError("cannot Subscribe to root channel") - return &subscribe.ID, errAnswer.Wrap("handleSubscribe") - } - - errAnswer := state2.Subscribe(socket, subscribe.Params.Channel) - if errAnswer != nil { - return &subscribe.ID, errAnswer.Wrap("handleSubscribe") - } - - socket.SendResult(subscribe.ID, nil, nil) - - return &subscribe.ID, nil -} - -func handleUnsubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { - var unsubscribe method.Unsubscribe - - err := json.Unmarshal(msg, &unsubscribe) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return nil, errAnswer.Wrap("handleUnsubscribe") - } - - if Root == unsubscribe.Params.Channel { - errAnswer := answer.NewInvalidActionError("cannot Unsubscribe from root channel") - return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") - } - - errAnswer := state2.Unsubscribe(socket, unsubscribe.Params.Channel) - if errAnswer != nil { - return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") - } - - socket.SendResult(unsubscribe.ID, nil, nil) - - return &unsubscribe.ID, nil -} - -func handleCatchUp(socket socket.Socket, msg []byte) (*int, *answer.Error) { - var catchup method.Catchup - - err := json.Unmarshal(msg, &catchup) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return nil, errAnswer.Wrap("handleCatchUp") - } - - db, errAnswer := database.GetQueryRepositoryInstance() - if errAnswer != nil { - return &catchup.ID, errAnswer.Wrap("handleCatchUp") - } - - result, err := db.GetAllMessagesFromChannel(catchup.Params.Channel) - if err != nil { - errAnswer := answer.NewQueryDatabaseError("all message from channel %s: %v", catchup.Params.Channel, err) - return &catchup.ID, errAnswer.Wrap("handleCatchUp") - } - - socket.SendResult(catchup.ID, result, nil) - - return &catchup.ID, nil -} - -func handleHeartbeat(socket socket.Socket, byteMessage []byte) *answer.Error { - var heartbeat method.Heartbeat - - err := json.Unmarshal(byteMessage, &heartbeat) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return errAnswer.Wrap("handleHeartbeat") - } - - db, errAnswer := database.GetQueryRepositoryInstance() - if errAnswer != nil { - return errAnswer.Wrap("handleHeartbeat") - } - - result, err := db.GetParamsForGetMessageByID(heartbeat.Params) - if err != nil { - errAnswer := answer.NewQueryDatabaseError("params for get messages by id: %v", err) - return errAnswer.Wrap("handleHeartbeat") - } - - if len(result) == 0 { - return nil - } - - queryId, errAnswer := state2.GetNextID() - if errAnswer != nil { - return errAnswer.Wrap("handleHeartbeat") - } - - getMessagesById := method.GetMessagesById{ - Base: query.Base{ - JSONRPCBase: jsonrpc.JSONRPCBase{ - JSONRPC: "2.0", - }, - Method: query.MethodGetMessagesById, - }, - ID: queryId, - Params: result, - } - - buf, err := json.Marshal(getMessagesById) - if err != nil { - errAnswer := answer.NewInternalServerError("failed to marshal: %v", err) - return errAnswer.Wrap("handleHeartbeat") - } - - socket.Send(buf) - - errAnswer = state2.AddQuery(queryId, getMessagesById) - if errAnswer != nil { - return errAnswer.Wrap("handleHeartbeat") - } - - return nil -} - -func handleGetMessagesByID(socket socket.Socket, msg []byte) (*int, *answer.Error) { - var getMessagesById method.GetMessagesById - - err := json.Unmarshal(msg, &getMessagesById) - if err != nil { - errAnswer := answer.NewJsonUnmarshalError(err.Error()) - return nil, errAnswer.Wrap("handleGetMessageByID") - } - - db, errAnswer := database.GetQueryRepositoryInstance() - if errAnswer != nil { - return &getMessagesById.ID, errAnswer.Wrap("handleGetMessageByID") - } - - result, err := db.GetResultForGetMessagesByID(getMessagesById.Params) - if err != nil { - errAnswer := answer.NewQueryDatabaseError("result for get messages by id: %v", err) - return &getMessagesById.ID, errAnswer.Wrap("handleGetMessageByID") - } - - socket.SendResult(getMessagesById.ID, nil, result) - - return &getMessagesById.ID, nil -} diff --git a/be1-go/internal/handler/query_test.go b/be1-go/internal/handler/query_test.go deleted file mode 100644 index c8c2c88b10..0000000000 --- a/be1-go/internal/handler/query_test.go +++ /dev/null @@ -1,647 +0,0 @@ -package handler - -import ( - "encoding/json" - "github.com/stretchr/testify/require" - "golang.org/x/xerrors" - "popstellar/internal/crypto" - "popstellar/internal/message/query/method" - "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" - "popstellar/internal/singleton/config" - "popstellar/internal/singleton/database" - "popstellar/internal/singleton/state" - "popstellar/internal/types" - "testing" -) - -func Test_handleQuery(t *testing.T) { - type input struct { - name string - message []byte - contains string - } - - args := make([]input, 0) - - // Test 1: failed to handled popquery because unknown method - - msg := generator.NewNothingQuery(t, 999) - - args = append(args, input{ - name: "Test 1", - message: msg, - contains: "unexpected method", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - fakeSocket := mocks.FakeSocket{Id: "fakesocket"} - errAnswer := handleQuery(&fakeSocket, arg.message) - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - }) - } -} - -func Test_handleGreetServer(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - serverSecretKey := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) - serverPublicKey := crypto.Suite.Point().Mul(serverSecretKey, nil) - - config.SetConfig(nil, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") - - type input struct { - name string - socket mocks.FakeSocket - message []byte - needGreet bool - isError bool - contains string - } - - args := make([]input, 0) - - greetServer := generator.NewGreetServerQuery(t, "pk", "client", "server") - - // Test 1: reply with greet server when receiving a greet server from a new server - - fakeSocket := mocks.FakeSocket{Id: "1"} - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - message: greetServer, - needGreet: true, - isError: false, - }) - - // Test 2: doesn't reply with greet server when already greeted the server - - fakeSocket = mocks.FakeSocket{Id: "2"} - - peers.AddPeerGreeted(fakeSocket.Id) - - args = append(args, input{ - name: "Test 2", - message: greetServer, - socket: fakeSocket, - needGreet: false, - isError: false, - }) - - // Test 3: return an error if the socket ID is already used by another server - - fakeSocket = mocks.FakeSocket{Id: "3"} - - err := peers.AddPeerInfo(fakeSocket.Id, method.GreetServerParams{}) - require.NoError(t, err) - - args = append(args, input{ - name: "Test 3", - socket: fakeSocket, - message: greetServer, - isError: true, - contains: "failed to add peer", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - id, errAnswer := handleGreetServer(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - require.Nil(t, id) - } else if arg.needGreet { - require.Nil(t, errAnswer) - require.NotNil(t, arg.socket.Msg) - } else { - require.Nil(t, errAnswer) - require.Nil(t, arg.socket.Msg) - } - }) - } -} - -func Test_handleSubscribe(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - type input struct { - name string - socket mocks.FakeSocket - ID int - channel string - message []byte - isError bool - contains string - } - - args := make([]input, 0) - - // Test 1: successfully subscribe to a channel - - fakeSocket := mocks.FakeSocket{Id: "1"} - ID := 1 - channel := "/root/lao1" - - errAnswer := subs.AddChannel(channel) - require.Nil(t, errAnswer) - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewSubscribeQuery(t, ID, channel), - isError: false, - }) - - // Test 2: failed to subscribe to an unknown channel - - fakeSocket = mocks.FakeSocket{Id: "2"} - ID = 2 - channel = "/root/lao2" - - args = append(args, input{ - name: "Test 2", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewSubscribeQuery(t, ID, channel), - isError: true, - contains: "cannot Subscribe to unknown channel", - }) - - // cannot Subscribe to root - - fakeSocket = mocks.FakeSocket{Id: "3"} - ID = 3 - channel = "/root" - - args = append(args, input{ - name: "Test 3", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewSubscribeQuery(t, ID, channel), - isError: true, - contains: "cannot Subscribe to root channel", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - id, errAnswer := handleSubscribe(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - require.Equal(t, arg.ID, *id) - } else { - require.Nil(t, errAnswer) - isSubscribed, err := subs.IsSubscribed(arg.channel, &arg.socket) - require.NoError(t, err) - require.True(t, isSubscribed) - } - }) - } -} - -func Test_handleUnsubscribe(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - type input struct { - name string - socket mocks.FakeSocket - ID int - channel string - message []byte - isError bool - contains string - } - - args := make([]input, 0) - - // Test 1: successfully unsubscribe from a subscribed channel - - fakeSocket := mocks.FakeSocket{Id: "1"} - ID := 1 - channel := "/root/lao1" - - errAnswer := subs.AddChannel(channel) - require.Nil(t, errAnswer) - - errAnswer = subs.Subscribe(channel, &fakeSocket) - require.Nil(t, errAnswer) - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewUnsubscribeQuery(t, ID, channel), - isError: false, - }) - - // Test 2: failed to unsubscribe because not subscribed to channel - - fakeSocket = mocks.FakeSocket{Id: "2"} - ID = 2 - channel = "/root/lao2" - - errAnswer = subs.AddChannel(channel) - require.Nil(t, errAnswer) - - args = append(args, input{ - name: "Test 2", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewUnsubscribeQuery(t, ID, channel), - isError: true, - contains: "cannot Unsubscribe from a channel not subscribed", - }) - - // Test 3: failed to unsubscribe because unknown channel - - fakeSocket = mocks.FakeSocket{Id: "3"} - ID = 3 - channel = "/root/lao3" - - args = append(args, input{ - name: "Test 3", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewUnsubscribeQuery(t, ID, channel), - isError: true, - contains: "cannot Unsubscribe from unknown channel", - }) - - // Test 3: failed to unsubscribe because cannot unsubscribe from root channel - - fakeSocket = mocks.FakeSocket{Id: "4"} - ID = 4 - channel = "/root" - - args = append(args, input{ - name: "Test 4", - socket: fakeSocket, - ID: ID, - channel: channel, - message: generator.NewUnsubscribeQuery(t, ID, channel), - isError: true, - contains: "cannot Unsubscribe from root channel", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - id, errAnswer := handleUnsubscribe(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - require.Equal(t, arg.ID, *id) - } else { - require.Nil(t, errAnswer) - - isSubscribe, err := subs.IsSubscribed(arg.channel, &arg.socket) - require.NoError(t, err) - require.False(t, isSubscribe) - } - }) - } -} - -func Test_handleCatchUp(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - mockRepository := mocks.NewRepository(t) - database.SetDatabase(mockRepository) - - type input struct { - name string - socket mocks.FakeSocket - ID int - message []byte - expected []message.Message - isError bool - contains string - } - - args := make([]input, 0) - - // Test 1: successfully catchup 4 messages on a channel - - fakeSocket := mocks.FakeSocket{Id: "1"} - ID := 1 - channel := "/root/lao1" - messagesToCatchUp := []message.Message{ - generator.NewNothingMsg(t, "sender1", nil), - generator.NewNothingMsg(t, "sender2", nil), - generator.NewNothingMsg(t, "sender3", nil), - generator.NewNothingMsg(t, "sender4", nil), - } - - mockRepository.On("GetAllMessagesFromChannel", channel).Return(messagesToCatchUp, nil) - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - ID: ID, - message: generator.NewCatchupQuery(t, ID, channel), - expected: messagesToCatchUp, - isError: false, - }) - - // Test 2: failed to catchup because DB is disconnected - - fakeSocket = mocks.FakeSocket{Id: "2"} - ID = 2 - channel = "/root/lao2" - - mockRepository.On("GetAllMessagesFromChannel", channel). - Return(nil, xerrors.Errorf("DB is disconnected")) - - args = append(args, input{ - name: "Test 2", - socket: fakeSocket, - ID: ID, - message: generator.NewCatchupQuery(t, ID, channel), - isError: true, - contains: "DB is disconnected", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - id, errAnswer := handleCatchUp(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - require.Contains(t, errAnswer.Error(), arg.contains) - require.NotNil(t, id) - require.Equal(t, arg.ID, *id) - } else { - require.Nil(t, errAnswer) - require.Equal(t, arg.expected, arg.socket.Res) - } - }) - } -} - -func Test_handleHeartbeat(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - mockRepository := mocks.NewRepository(t) - database.SetDatabase(mockRepository) - - type input struct { - name string - socket mocks.FakeSocket - message []byte - expected map[string][]string - isError bool - contains string - } - - msgIDs := []string{"msg0", "msg1", "msg2", "msg3", "msg4", "msg5", "msg6"} - - args := make([]input, 0) - - // Test 1: successfully handled heartbeat with some messages to catching up - - fakeSocket := mocks.FakeSocket{Id: "1"} - - heartbeatMsgIDs1 := make(map[string][]string) - heartbeatMsgIDs1["/root"] = []string{ - msgIDs[0], - msgIDs[1], - msgIDs[2], - } - heartbeatMsgIDs1["root/lao1"] = []string{ - msgIDs[3], - msgIDs[4], - } - heartbeatMsgIDs1["root/lao2"] = []string{ - msgIDs[5], - msgIDs[6], - } - - expected1 := make(map[string][]string) - expected1["/root"] = []string{ - msgIDs[1], - msgIDs[2], - } - expected1["root/lao1"] = []string{ - msgIDs[4], - } - - mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs1).Return(expected1, nil) - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs1), - expected: expected1, - isError: false, - }) - - // Test 2: successfully handled heartbeat with nothing to catching up - - fakeSocket = mocks.FakeSocket{Id: "2"} - - heartbeatMsgIDs2 := make(map[string][]string) - heartbeatMsgIDs2["/root"] = []string{ - msgIDs[0], - msgIDs[1], - msgIDs[2], - } - - mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs2).Return(nil, nil) - - args = append(args, input{ - name: "Test 2", - socket: fakeSocket, - message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs2), - isError: false, - }) - - // Test 3: failed to handled heartbeat because DB is disconnected - - fakeSocket = mocks.FakeSocket{Id: "3"} - - heartbeatMsgIDs3 := make(map[string][]string) - heartbeatMsgIDs3["/root"] = []string{ - msgIDs[0], - msgIDs[1], - msgIDs[2], - } - heartbeatMsgIDs3["root/lao1"] = []string{ - msgIDs[3], - msgIDs[4], - } - - mockRepository.On("GetParamsForGetMessageByID", heartbeatMsgIDs3). - Return(nil, xerrors.Errorf("DB is disconnected")) - - args = append(args, input{ - name: "failed to popquery DB", - socket: fakeSocket, - message: generator.NewHeartbeatQuery(t, heartbeatMsgIDs3), - isError: true, - contains: "DB is disconnected", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - errAnswer := handleHeartbeat(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - } else if arg.expected != nil { - require.Nil(t, errAnswer) - require.NotNil(t, arg.socket.Msg) - - var getMessageByID method.GetMessagesById - err := json.Unmarshal(arg.socket.Msg, &getMessageByID) - require.NoError(t, err) - - require.Equal(t, arg.expected, getMessageByID.Params) - } else { - require.Nil(t, errAnswer) - require.Nil(t, arg.socket.Msg) - } - }) - } -} - -func Test_handleGetMessagesByID(t *testing.T) { - subs := types.NewSubscribers() - queries := types.NewQueries(&noLog) - peers := types.NewPeers() - hubParams := types.NewHubParams() - - state.SetState(subs, peers, queries, hubParams) - - mockRepository := mocks.NewRepository(t) - database.SetDatabase(mockRepository) - - type input struct { - name string - socket mocks.FakeSocket - ID int - message []byte - expected map[string][]message.Message - isError bool - contains string - } - - args := make([]input, 0) - - // Test 1: successfully handled getMessagesByID and sent the result - - fakeSocket := mocks.FakeSocket{Id: "1"} - ID := 1 - - expected1 := make(map[string][]message.Message) - expected1["/root"] = []message.Message{ - generator.NewNothingMsg(t, "sender1", nil), - generator.NewNothingMsg(t, "sender2", nil), - generator.NewNothingMsg(t, "sender3", nil), - generator.NewNothingMsg(t, "sender4", nil), - } - expected1["/root/lao1"] = []message.Message{ - generator.NewNothingMsg(t, "sender5", nil), - generator.NewNothingMsg(t, "sender6", nil), - } - - paramsGetMessagesByID1 := make(map[string][]string) - for k, v := range expected1 { - paramsGetMessagesByID1[k] = make([]string, 0) - for _, w := range v { - paramsGetMessagesByID1[k] = append(paramsGetMessagesByID1[k], w.MessageID) - } - } - - mockRepository.On("GetResultForGetMessagesByID", paramsGetMessagesByID1).Return(expected1, nil) - - args = append(args, input{ - name: "Test 1", - socket: fakeSocket, - ID: ID, - message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID1), - expected: expected1, - isError: false, - }) - - // Test 2: failed to handled getMessagesByID because DB is disconnected - - fakeSocket = mocks.FakeSocket{Id: "2"} - ID = 2 - - paramsGetMessagesByID2 := make(map[string][]string) - - mockRepository.On("GetResultForGetMessagesByID", paramsGetMessagesByID2). - Return(nil, xerrors.Errorf("DB is disconnected")) - - args = append(args, input{ - name: "Test 2", - socket: fakeSocket, - ID: ID, - message: generator.NewGetMessagesByIDQuery(t, ID, paramsGetMessagesByID2), - isError: true, - contains: "DB is disconnected", - }) - - // run all tests - - for _, arg := range args { - t.Run(arg.name, func(t *testing.T) { - id, errAnswer := handleGetMessagesByID(&arg.socket, arg.message) - if arg.isError { - require.NotNil(t, errAnswer) - require.NotNil(t, id) - require.Contains(t, errAnswer.Error(), arg.contains) - require.Equal(t, arg.ID, *id) - } else { - require.Nil(t, errAnswer) - require.NotNil(t, arg.expected) - require.Equal(t, arg.expected, arg.socket.MissingMsgs) - } - }) - } -} diff --git a/be1-go/internal/hub/hub.go b/be1-go/internal/hub/hub.go index b9a382f61e..97ab7f6c1f 100644 --- a/be1-go/internal/hub/hub.go +++ b/be1-go/internal/hub/hub.go @@ -3,7 +3,7 @@ package hub import ( "encoding/json" "golang.org/x/xerrors" - "popstellar/internal/handler" + "popstellar/internal/handler/low" "popstellar/internal/logger" jsonrpc "popstellar/internal/message" "popstellar/internal/message/query" @@ -123,7 +123,7 @@ func (h *Hub) Start() { select { case incomingMessage := <-h.messageChan: utils.LogInfo("start handling a message") - err := handler.HandleIncomingMessage(incomingMessage.Socket, incomingMessage.Message) + err := low.HandleIncomingMessage(incomingMessage.Socket, incomingMessage.Message) if err != nil { utils.LogError(err) } else { @@ -229,5 +229,5 @@ func (h *Hub) tryToSendRumor() { return } - handler.SendRumor(nil, rumor) + low.SendRumor(nil, rumor) } diff --git a/be1-go/internal/mocks/generator/keys.go b/be1-go/internal/mocks/generator/keys.go new file mode 100644 index 0000000000..072f748723 --- /dev/null +++ b/be1-go/internal/mocks/generator/keys.go @@ -0,0 +1,27 @@ +package generator + +import ( + "github.com/stretchr/testify/require" + "go.dedis.ch/kyber/v3" + "popstellar/internal/crypto" + "testing" +) + +type Keypair struct { + Public kyber.Point + PublicBuf []byte + Private kyber.Scalar + PrivateBuf []byte +} + +func GenerateKeyPair(t *testing.T) Keypair { + secret := crypto.Suite.Scalar().Pick(crypto.Suite.RandomStream()) + point := crypto.Suite.Point().Mul(secret, nil) + + publicBuf, err := point.MarshalBinary() + require.NoError(t, err) + privateBuf, err := secret.MarshalBinary() + require.NoError(t, err) + + return Keypair{point, publicBuf, secret, privateBuf} +} From e138b61d275adf30570176acb6360421c5f8386e Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 16:43:13 +0200 Subject: [PATCH 08/19] separate low in two packages --- .../handler/low/{ => answer}/answer.go | 7 ++--- .../handler/low/{ => answer}/answer_test.go | 23 +++++++++++++++- .../internal/handler/low/incoming_message.go | 6 +++-- .../handler/low/{ => query}/catchup.go | 2 +- .../handler/low/{ => query}/catchup_test.go | 2 +- .../low/{ => query}/getmessagesbyid.go | 2 +- .../low/{ => query}/getmessagesbyid_test.go | 2 +- .../handler/low/{ => query}/greetserver.go | 2 +- .../low/{ => query}/greetserver_test.go | 2 +- .../handler/low/{ => query}/heartbeat.go | 2 +- .../handler/low/{ => query}/heartbeat_test.go | 2 +- .../handler/low/{ => query}/publish.go | 2 +- .../internal/handler/low/{ => query}/query.go | 8 +++--- .../handler/low/{ => query}/query_test.go | 26 +++++++++++++++++-- .../internal/handler/low/{ => query}/rumor.go | 12 +++++---- .../handler/low/{ => query}/subscribe.go | 2 +- .../handler/low/{ => query}/subscribe_test.go | 2 +- .../handler/low/{ => query}/unsubscribe.go | 2 +- .../low/{ => query}/unsubscribe_test.go | 2 +- be1-go/internal/hub/hub.go | 3 ++- 20 files changed, 80 insertions(+), 31 deletions(-) rename be1-go/internal/handler/low/{ => answer}/answer.go (97%) rename be1-go/internal/handler/low/{ => answer}/answer_test.go (88%) rename be1-go/internal/handler/low/{ => query}/catchup.go (98%) rename be1-go/internal/handler/low/{ => query}/catchup_test.go (99%) rename be1-go/internal/handler/low/{ => query}/getmessagesbyid.go (98%) rename be1-go/internal/handler/low/{ => query}/getmessagesbyid_test.go (99%) rename be1-go/internal/handler/low/{ => query}/greetserver.go (99%) rename be1-go/internal/handler/low/{ => query}/greetserver_test.go (99%) rename be1-go/internal/handler/low/{ => query}/heartbeat.go (99%) rename be1-go/internal/handler/low/{ => query}/heartbeat_test.go (99%) rename be1-go/internal/handler/low/{ => query}/publish.go (99%) rename be1-go/internal/handler/low/{ => query}/query.go (89%) rename be1-go/internal/handler/low/{ => query}/query_test.go (60%) rename be1-go/internal/handler/low/{ => query}/rumor.go (94%) rename be1-go/internal/handler/low/{ => query}/subscribe.go (98%) rename be1-go/internal/handler/low/{ => query}/subscribe_test.go (99%) rename be1-go/internal/handler/low/{ => query}/unsubscribe.go (98%) rename be1-go/internal/handler/low/{ => query}/unsubscribe_test.go (99%) diff --git a/be1-go/internal/handler/low/answer.go b/be1-go/internal/handler/low/answer/answer.go similarity index 97% rename from be1-go/internal/handler/low/answer.go rename to be1-go/internal/handler/low/answer/answer.go index afbcb5d897..2df9faba78 100644 --- a/be1-go/internal/handler/low/answer.go +++ b/be1-go/internal/handler/low/answer/answer.go @@ -1,9 +1,10 @@ -package low +package answer import ( "encoding/json" "math/rand" "popstellar/internal/handler/high" + "popstellar/internal/handler/low/query" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method/message" @@ -16,7 +17,7 @@ const ( continueMongering = 0.5 ) -func handleAnswer(msg []byte) *answer.Error { +func HandleAnswer(msg []byte) *answer.Error { var answerMsg answer.Answer err := json.Unmarshal(msg, &answerMsg) @@ -92,7 +93,7 @@ func handleRumorAnswer(msg answer.Answer) *answer.Error { return answer.NewInternalServerError("rumor query %d doesn't exist", *msg.ID) } - SendRumor(nil, rumor) + query.SendRumor(nil, rumor) return nil } diff --git a/be1-go/internal/handler/low/answer_test.go b/be1-go/internal/handler/low/answer/answer_test.go similarity index 88% rename from be1-go/internal/handler/low/answer_test.go rename to be1-go/internal/handler/low/answer/answer_test.go index c1dbdf2f31..ee2a781bc6 100644 --- a/be1-go/internal/handler/low/answer_test.go +++ b/be1-go/internal/handler/low/answer/answer_test.go @@ -1,21 +1,42 @@ -package low +package answer import ( "encoding/base64" "encoding/json" "fmt" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" "go.dedis.ch/kyber/v3/sign/schnorr" + "io" + "os" "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" "popstellar/internal/mocks" "popstellar/internal/mocks/generator" "popstellar/internal/singleton/database" + "popstellar/internal/singleton/utils" + "popstellar/internal/validation" "testing" "time" ) +var noLog = zerolog.New(io.Discard) + +func TestMain(m *testing.M) { + schemaValidator, err := validation.NewSchemaValidator() + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + utils.InitUtils(&noLog, schemaValidator) + + exitVal := m.Run() + + os.Exit(exitVal) +} + func Test_handleMessagesByChannel(t *testing.T) { mockRepository := mocks.NewRepository(t) database.SetDatabase(mockRepository) diff --git a/be1-go/internal/handler/low/incoming_message.go b/be1-go/internal/handler/low/incoming_message.go index c22cc71ba0..b49d4bd61d 100644 --- a/be1-go/internal/handler/low/incoming_message.go +++ b/be1-go/internal/handler/low/incoming_message.go @@ -1,6 +1,8 @@ package low import ( + jsonrpc "popstellar/internal/handler/low/answer" + "popstellar/internal/handler/low/query" "popstellar/internal/message" "popstellar/internal/message/answer" "popstellar/internal/network/socket" @@ -25,9 +27,9 @@ func HandleIncomingMessage(socket socket.Socket, msg []byte) error { switch rpcType { case message.RPCTypeQuery: - errAnswer = handleQuery(socket, msg) + errAnswer = query.HandleQuery(socket, msg) case message.RPCTypeAnswer: - errAnswer = handleAnswer(msg) + errAnswer = jsonrpc.HandleAnswer(msg) default: errAnswer = answer.NewInvalidMessageFieldError("jsonRPC is of unknown type") } diff --git a/be1-go/internal/handler/low/catchup.go b/be1-go/internal/handler/low/query/catchup.go similarity index 98% rename from be1-go/internal/handler/low/catchup.go rename to be1-go/internal/handler/low/query/catchup.go index 1c36c1a708..bc3b513147 100644 --- a/be1-go/internal/handler/low/catchup.go +++ b/be1-go/internal/handler/low/query/catchup.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/catchup_test.go b/be1-go/internal/handler/low/query/catchup_test.go similarity index 99% rename from be1-go/internal/handler/low/catchup_test.go rename to be1-go/internal/handler/low/query/catchup_test.go index 43da69bc62..bb748040f2 100644 --- a/be1-go/internal/handler/low/catchup_test.go +++ b/be1-go/internal/handler/low/query/catchup_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "github.com/stretchr/testify/require" diff --git a/be1-go/internal/handler/low/getmessagesbyid.go b/be1-go/internal/handler/low/query/getmessagesbyid.go similarity index 98% rename from be1-go/internal/handler/low/getmessagesbyid.go rename to be1-go/internal/handler/low/query/getmessagesbyid.go index 537954ddfc..d5dce76d6e 100644 --- a/be1-go/internal/handler/low/getmessagesbyid.go +++ b/be1-go/internal/handler/low/query/getmessagesbyid.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/getmessagesbyid_test.go b/be1-go/internal/handler/low/query/getmessagesbyid_test.go similarity index 99% rename from be1-go/internal/handler/low/getmessagesbyid_test.go rename to be1-go/internal/handler/low/query/getmessagesbyid_test.go index ee312cc794..f8a9359892 100644 --- a/be1-go/internal/handler/low/getmessagesbyid_test.go +++ b/be1-go/internal/handler/low/query/getmessagesbyid_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "github.com/stretchr/testify/require" diff --git a/be1-go/internal/handler/low/greetserver.go b/be1-go/internal/handler/low/query/greetserver.go similarity index 99% rename from be1-go/internal/handler/low/greetserver.go rename to be1-go/internal/handler/low/query/greetserver.go index d70371f201..6776193cdb 100644 --- a/be1-go/internal/handler/low/greetserver.go +++ b/be1-go/internal/handler/low/query/greetserver.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/greetserver_test.go b/be1-go/internal/handler/low/query/greetserver_test.go similarity index 99% rename from be1-go/internal/handler/low/greetserver_test.go rename to be1-go/internal/handler/low/query/greetserver_test.go index b999cbbb33..77657ea071 100644 --- a/be1-go/internal/handler/low/greetserver_test.go +++ b/be1-go/internal/handler/low/query/greetserver_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "github.com/stretchr/testify/require" diff --git a/be1-go/internal/handler/low/heartbeat.go b/be1-go/internal/handler/low/query/heartbeat.go similarity index 99% rename from be1-go/internal/handler/low/heartbeat.go rename to be1-go/internal/handler/low/query/heartbeat.go index 723564803a..61af71ac02 100644 --- a/be1-go/internal/handler/low/heartbeat.go +++ b/be1-go/internal/handler/low/query/heartbeat.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/heartbeat_test.go b/be1-go/internal/handler/low/query/heartbeat_test.go similarity index 99% rename from be1-go/internal/handler/low/heartbeat_test.go rename to be1-go/internal/handler/low/query/heartbeat_test.go index 5b516dcaac..50da019764 100644 --- a/be1-go/internal/handler/low/heartbeat_test.go +++ b/be1-go/internal/handler/low/query/heartbeat_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/publish.go b/be1-go/internal/handler/low/query/publish.go similarity index 99% rename from be1-go/internal/handler/low/publish.go rename to be1-go/internal/handler/low/query/publish.go index f50bbbfc64..4f3ecb0f5a 100644 --- a/be1-go/internal/handler/low/publish.go +++ b/be1-go/internal/handler/low/query/publish.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/query.go b/be1-go/internal/handler/low/query/query.go similarity index 89% rename from be1-go/internal/handler/low/query.go rename to be1-go/internal/handler/low/query/query.go index 2f144a5793..3b5bdbcd3d 100644 --- a/be1-go/internal/handler/low/query.go +++ b/be1-go/internal/handler/low/query/query.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" @@ -7,12 +7,12 @@ import ( "popstellar/internal/network/socket" ) -func handleQuery(socket socket.Socket, msg []byte) *answer.Error { +func HandleQuery(socket socket.Socket, msg []byte) *answer.Error { var queryBase query.Base err := json.Unmarshal(msg, &queryBase) if err != nil { - errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("handleQuery") + errAnswer := answer.NewInvalidMessageFieldError("failed to unmarshal: %v", err).Wrap("HandleQuery") socket.SendError(nil, errAnswer) return errAnswer } @@ -42,7 +42,7 @@ func handleQuery(socket socket.Socket, msg []byte) *answer.Error { } if errAnswer != nil && queryBase.Method != query.MethodGreetServer && queryBase.Method != query.MethodHeartbeat { - errAnswer = errAnswer.Wrap("handleQuery") + errAnswer = errAnswer.Wrap("HandleQuery") socket.SendError(id, errAnswer) return errAnswer } diff --git a/be1-go/internal/handler/low/query_test.go b/be1-go/internal/handler/low/query/query_test.go similarity index 60% rename from be1-go/internal/handler/low/query_test.go rename to be1-go/internal/handler/low/query/query_test.go index 36ef3ce594..58c9824421 100644 --- a/be1-go/internal/handler/low/query_test.go +++ b/be1-go/internal/handler/low/query/query_test.go @@ -1,12 +1,34 @@ -package low +package query import ( + "fmt" + "github.com/rs/zerolog" "github.com/stretchr/testify/require" + "io" + "os" "popstellar/internal/mocks" "popstellar/internal/mocks/generator" + "popstellar/internal/singleton/utils" + "popstellar/internal/validation" "testing" ) +var noLog = zerolog.New(io.Discard) + +func TestMain(m *testing.M) { + schemaValidator, err := validation.NewSchemaValidator() + if err != nil { + _, _ = fmt.Fprintf(os.Stderr, "error: %v\n", err) + os.Exit(1) + } + + utils.InitUtils(&noLog, schemaValidator) + + exitVal := m.Run() + + os.Exit(exitVal) +} + func Test_handleQuery(t *testing.T) { type input struct { name string @@ -31,7 +53,7 @@ func Test_handleQuery(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { fakeSocket := mocks.FakeSocket{Id: "fakesocket"} - errAnswer := handleQuery(&fakeSocket, arg.message) + errAnswer := HandleQuery(&fakeSocket, arg.message) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/low/rumor.go b/be1-go/internal/handler/low/query/rumor.go similarity index 94% rename from be1-go/internal/handler/low/rumor.go rename to be1-go/internal/handler/low/query/rumor.go index f9fe9ab2e2..75ea802435 100644 --- a/be1-go/internal/handler/low/rumor.go +++ b/be1-go/internal/handler/low/query/rumor.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" @@ -9,11 +9,13 @@ import ( "popstellar/internal/message/query/method/message" "popstellar/internal/network/socket" "popstellar/internal/singleton/database" - state2 "popstellar/internal/singleton/state" + "popstellar/internal/singleton/state" "popstellar/internal/singleton/utils" "sort" ) +const maxRetry = 10 + func handleRumor(socket socket.Socket, msg []byte) (*int, *answer.Error) { var rumor method.Rumor @@ -131,7 +133,7 @@ func sortChannels(msgsByChannel map[string][]message.Message) []string { } func SendRumor(socket socket.Socket, rumor method.Rumor) { - id, errAnswer := state2.GetNextID() + id, errAnswer := state.GetNextID() if errAnswer != nil { logger.Logger.Error().Err(errAnswer) return @@ -139,7 +141,7 @@ func SendRumor(socket socket.Socket, rumor method.Rumor) { rumor.ID = id - errAnswer = state2.AddRumorQuery(id, rumor) + errAnswer = state.AddRumorQuery(id, rumor) if errAnswer != nil { logger.Logger.Error().Err(errAnswer) return @@ -152,7 +154,7 @@ func SendRumor(socket socket.Socket, rumor method.Rumor) { } logger.Logger.Debug().Msgf("sending rumor %s-%d query %d", rumor.Params.SenderID, rumor.Params.RumorID, rumor.ID) - errAnswer = state2.SendRumor(socket, rumor.Params.SenderID, rumor.Params.RumorID, buf) + errAnswer = state.SendRumor(socket, rumor.Params.SenderID, rumor.Params.RumorID, buf) if errAnswer != nil { logger.Logger.Err(errAnswer) } diff --git a/be1-go/internal/handler/low/subscribe.go b/be1-go/internal/handler/low/query/subscribe.go similarity index 98% rename from be1-go/internal/handler/low/subscribe.go rename to be1-go/internal/handler/low/query/subscribe.go index 54fec00dac..1d6842fe28 100644 --- a/be1-go/internal/handler/low/subscribe.go +++ b/be1-go/internal/handler/low/query/subscribe.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/subscribe_test.go b/be1-go/internal/handler/low/query/subscribe_test.go similarity index 99% rename from be1-go/internal/handler/low/subscribe_test.go rename to be1-go/internal/handler/low/query/subscribe_test.go index 84353723aa..f01402d5ef 100644 --- a/be1-go/internal/handler/low/subscribe_test.go +++ b/be1-go/internal/handler/low/query/subscribe_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "github.com/stretchr/testify/require" diff --git a/be1-go/internal/handler/low/unsubscribe.go b/be1-go/internal/handler/low/query/unsubscribe.go similarity index 98% rename from be1-go/internal/handler/low/unsubscribe.go rename to be1-go/internal/handler/low/query/unsubscribe.go index c33fe3fe19..cb33f69183 100644 --- a/be1-go/internal/handler/low/unsubscribe.go +++ b/be1-go/internal/handler/low/query/unsubscribe.go @@ -1,4 +1,4 @@ -package low +package query import ( "encoding/json" diff --git a/be1-go/internal/handler/low/unsubscribe_test.go b/be1-go/internal/handler/low/query/unsubscribe_test.go similarity index 99% rename from be1-go/internal/handler/low/unsubscribe_test.go rename to be1-go/internal/handler/low/query/unsubscribe_test.go index a5c99d7675..8ceaa35800 100644 --- a/be1-go/internal/handler/low/unsubscribe_test.go +++ b/be1-go/internal/handler/low/query/unsubscribe_test.go @@ -1,4 +1,4 @@ -package low +package query import ( "github.com/stretchr/testify/require" diff --git a/be1-go/internal/hub/hub.go b/be1-go/internal/hub/hub.go index 97ab7f6c1f..7521c5b270 100644 --- a/be1-go/internal/hub/hub.go +++ b/be1-go/internal/hub/hub.go @@ -4,6 +4,7 @@ import ( "encoding/json" "golang.org/x/xerrors" "popstellar/internal/handler/low" + query2 "popstellar/internal/handler/low/query" "popstellar/internal/logger" jsonrpc "popstellar/internal/message" "popstellar/internal/message/query" @@ -229,5 +230,5 @@ func (h *Hub) tryToSendRumor() { return } - low.SendRumor(nil, rumor) + query2.SendRumor(nil, rumor) } From c555a43a910ada53e50e6380955a7390a4eee2e4 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 16:51:54 +0200 Subject: [PATCH 09/19] rename fake socket --- be1-go/internal/mocks/{fake_socket.go => socket.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename be1-go/internal/mocks/{fake_socket.go => socket.go} (100%) diff --git a/be1-go/internal/mocks/fake_socket.go b/be1-go/internal/mocks/socket.go similarity index 100% rename from be1-go/internal/mocks/fake_socket.go rename to be1-go/internal/mocks/socket.go From c7a930ced76bae71407dfae0e070f6653563bec1 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 16:56:18 +0200 Subject: [PATCH 10/19] rename low directory --- be1-go/internal/handler/{low => }/answer/answer.go | 2 +- be1-go/internal/handler/{low => }/answer/answer_test.go | 0 be1-go/internal/handler/{low => }/incoming_message.go | 6 +++--- be1-go/internal/handler/{low => }/incoming_message_test.go | 2 +- be1-go/internal/handler/{low => }/query/catchup.go | 0 be1-go/internal/handler/{low => }/query/catchup_test.go | 0 be1-go/internal/handler/{low => }/query/getmessagesbyid.go | 0 .../handler/{low => }/query/getmessagesbyid_test.go | 0 be1-go/internal/handler/{low => }/query/greetserver.go | 0 be1-go/internal/handler/{low => }/query/greetserver_test.go | 0 be1-go/internal/handler/{low => }/query/heartbeat.go | 0 be1-go/internal/handler/{low => }/query/heartbeat_test.go | 0 be1-go/internal/handler/{low => }/query/publish.go | 0 be1-go/internal/handler/{low => }/query/query.go | 0 be1-go/internal/handler/{low => }/query/query_test.go | 0 be1-go/internal/handler/{low => }/query/rumor.go | 0 be1-go/internal/handler/{low => }/query/subscribe.go | 0 be1-go/internal/handler/{low => }/query/subscribe_test.go | 0 be1-go/internal/handler/{low => }/query/unsubscribe.go | 0 be1-go/internal/handler/{low => }/query/unsubscribe_test.go | 0 be1-go/internal/hub/hub.go | 6 +++--- 21 files changed, 8 insertions(+), 8 deletions(-) rename be1-go/internal/handler/{low => }/answer/answer.go (99%) rename be1-go/internal/handler/{low => }/answer/answer_test.go (100%) rename be1-go/internal/handler/{low => }/incoming_message.go (90%) rename be1-go/internal/handler/{low => }/incoming_message_test.go (98%) rename be1-go/internal/handler/{low => }/query/catchup.go (100%) rename be1-go/internal/handler/{low => }/query/catchup_test.go (100%) rename be1-go/internal/handler/{low => }/query/getmessagesbyid.go (100%) rename be1-go/internal/handler/{low => }/query/getmessagesbyid_test.go (100%) rename be1-go/internal/handler/{low => }/query/greetserver.go (100%) rename be1-go/internal/handler/{low => }/query/greetserver_test.go (100%) rename be1-go/internal/handler/{low => }/query/heartbeat.go (100%) rename be1-go/internal/handler/{low => }/query/heartbeat_test.go (100%) rename be1-go/internal/handler/{low => }/query/publish.go (100%) rename be1-go/internal/handler/{low => }/query/query.go (100%) rename be1-go/internal/handler/{low => }/query/query_test.go (100%) rename be1-go/internal/handler/{low => }/query/rumor.go (100%) rename be1-go/internal/handler/{low => }/query/subscribe.go (100%) rename be1-go/internal/handler/{low => }/query/subscribe_test.go (100%) rename be1-go/internal/handler/{low => }/query/unsubscribe.go (100%) rename be1-go/internal/handler/{low => }/query/unsubscribe_test.go (100%) diff --git a/be1-go/internal/handler/low/answer/answer.go b/be1-go/internal/handler/answer/answer.go similarity index 99% rename from be1-go/internal/handler/low/answer/answer.go rename to be1-go/internal/handler/answer/answer.go index 2df9faba78..df0c48dad7 100644 --- a/be1-go/internal/handler/low/answer/answer.go +++ b/be1-go/internal/handler/answer/answer.go @@ -4,7 +4,7 @@ import ( "encoding/json" "math/rand" "popstellar/internal/handler/high" - "popstellar/internal/handler/low/query" + "popstellar/internal/handler/query" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method/message" diff --git a/be1-go/internal/handler/low/answer/answer_test.go b/be1-go/internal/handler/answer/answer_test.go similarity index 100% rename from be1-go/internal/handler/low/answer/answer_test.go rename to be1-go/internal/handler/answer/answer_test.go diff --git a/be1-go/internal/handler/low/incoming_message.go b/be1-go/internal/handler/incoming_message.go similarity index 90% rename from be1-go/internal/handler/low/incoming_message.go rename to be1-go/internal/handler/incoming_message.go index b49d4bd61d..99bc42b0b6 100644 --- a/be1-go/internal/handler/low/incoming_message.go +++ b/be1-go/internal/handler/incoming_message.go @@ -1,8 +1,8 @@ -package low +package handler import ( - jsonrpc "popstellar/internal/handler/low/answer" - "popstellar/internal/handler/low/query" + jsonrpc "popstellar/internal/handler/answer" + "popstellar/internal/handler/query" "popstellar/internal/message" "popstellar/internal/message/answer" "popstellar/internal/network/socket" diff --git a/be1-go/internal/handler/low/incoming_message_test.go b/be1-go/internal/handler/incoming_message_test.go similarity index 98% rename from be1-go/internal/handler/low/incoming_message_test.go rename to be1-go/internal/handler/incoming_message_test.go index 4994054de4..99f4620011 100644 --- a/be1-go/internal/handler/low/incoming_message_test.go +++ b/be1-go/internal/handler/incoming_message_test.go @@ -1,4 +1,4 @@ -package low +package handler import ( "encoding/base64" diff --git a/be1-go/internal/handler/low/query/catchup.go b/be1-go/internal/handler/query/catchup.go similarity index 100% rename from be1-go/internal/handler/low/query/catchup.go rename to be1-go/internal/handler/query/catchup.go diff --git a/be1-go/internal/handler/low/query/catchup_test.go b/be1-go/internal/handler/query/catchup_test.go similarity index 100% rename from be1-go/internal/handler/low/query/catchup_test.go rename to be1-go/internal/handler/query/catchup_test.go diff --git a/be1-go/internal/handler/low/query/getmessagesbyid.go b/be1-go/internal/handler/query/getmessagesbyid.go similarity index 100% rename from be1-go/internal/handler/low/query/getmessagesbyid.go rename to be1-go/internal/handler/query/getmessagesbyid.go diff --git a/be1-go/internal/handler/low/query/getmessagesbyid_test.go b/be1-go/internal/handler/query/getmessagesbyid_test.go similarity index 100% rename from be1-go/internal/handler/low/query/getmessagesbyid_test.go rename to be1-go/internal/handler/query/getmessagesbyid_test.go diff --git a/be1-go/internal/handler/low/query/greetserver.go b/be1-go/internal/handler/query/greetserver.go similarity index 100% rename from be1-go/internal/handler/low/query/greetserver.go rename to be1-go/internal/handler/query/greetserver.go diff --git a/be1-go/internal/handler/low/query/greetserver_test.go b/be1-go/internal/handler/query/greetserver_test.go similarity index 100% rename from be1-go/internal/handler/low/query/greetserver_test.go rename to be1-go/internal/handler/query/greetserver_test.go diff --git a/be1-go/internal/handler/low/query/heartbeat.go b/be1-go/internal/handler/query/heartbeat.go similarity index 100% rename from be1-go/internal/handler/low/query/heartbeat.go rename to be1-go/internal/handler/query/heartbeat.go diff --git a/be1-go/internal/handler/low/query/heartbeat_test.go b/be1-go/internal/handler/query/heartbeat_test.go similarity index 100% rename from be1-go/internal/handler/low/query/heartbeat_test.go rename to be1-go/internal/handler/query/heartbeat_test.go diff --git a/be1-go/internal/handler/low/query/publish.go b/be1-go/internal/handler/query/publish.go similarity index 100% rename from be1-go/internal/handler/low/query/publish.go rename to be1-go/internal/handler/query/publish.go diff --git a/be1-go/internal/handler/low/query/query.go b/be1-go/internal/handler/query/query.go similarity index 100% rename from be1-go/internal/handler/low/query/query.go rename to be1-go/internal/handler/query/query.go diff --git a/be1-go/internal/handler/low/query/query_test.go b/be1-go/internal/handler/query/query_test.go similarity index 100% rename from be1-go/internal/handler/low/query/query_test.go rename to be1-go/internal/handler/query/query_test.go diff --git a/be1-go/internal/handler/low/query/rumor.go b/be1-go/internal/handler/query/rumor.go similarity index 100% rename from be1-go/internal/handler/low/query/rumor.go rename to be1-go/internal/handler/query/rumor.go diff --git a/be1-go/internal/handler/low/query/subscribe.go b/be1-go/internal/handler/query/subscribe.go similarity index 100% rename from be1-go/internal/handler/low/query/subscribe.go rename to be1-go/internal/handler/query/subscribe.go diff --git a/be1-go/internal/handler/low/query/subscribe_test.go b/be1-go/internal/handler/query/subscribe_test.go similarity index 100% rename from be1-go/internal/handler/low/query/subscribe_test.go rename to be1-go/internal/handler/query/subscribe_test.go diff --git a/be1-go/internal/handler/low/query/unsubscribe.go b/be1-go/internal/handler/query/unsubscribe.go similarity index 100% rename from be1-go/internal/handler/low/query/unsubscribe.go rename to be1-go/internal/handler/query/unsubscribe.go diff --git a/be1-go/internal/handler/low/query/unsubscribe_test.go b/be1-go/internal/handler/query/unsubscribe_test.go similarity index 100% rename from be1-go/internal/handler/low/query/unsubscribe_test.go rename to be1-go/internal/handler/query/unsubscribe_test.go diff --git a/be1-go/internal/hub/hub.go b/be1-go/internal/hub/hub.go index 7521c5b270..1261112818 100644 --- a/be1-go/internal/hub/hub.go +++ b/be1-go/internal/hub/hub.go @@ -3,8 +3,8 @@ package hub import ( "encoding/json" "golang.org/x/xerrors" - "popstellar/internal/handler/low" - query2 "popstellar/internal/handler/low/query" + "popstellar/internal/handler" + query2 "popstellar/internal/handler/query" "popstellar/internal/logger" jsonrpc "popstellar/internal/message" "popstellar/internal/message/query" @@ -124,7 +124,7 @@ func (h *Hub) Start() { select { case incomingMessage := <-h.messageChan: utils.LogInfo("start handling a message") - err := low.HandleIncomingMessage(incomingMessage.Socket, incomingMessage.Message) + err := handler.HandleIncomingMessage(incomingMessage.Socket, incomingMessage.Message) if err != nil { utils.LogError(err) } else { From c7560a91820909bd5306e2fe40b02ba2b1f2038e Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 17:05:08 +0200 Subject: [PATCH 11/19] rename channel to channelPath --- be1-go/internal/handler/high/channel.go | 4 +- be1-go/internal/handler/high/channel_test.go | 38 ++-- be1-go/internal/handler/high/chirp.go | 4 +- be1-go/internal/handler/high/chirp_test.go | 78 ++++----- be1-go/internal/handler/high/coin_test.go | 16 +- be1-go/internal/handler/high/election_test.go | 140 +++++++-------- be1-go/internal/handler/high/federation.go | 30 ++-- .../internal/handler/high/federation_test.go | 84 ++++----- be1-go/internal/handler/high/lao_test.go | 162 +++++++++--------- be1-go/internal/handler/high/reaction.go | 8 +- be1-go/internal/handler/high/reaction_test.go | 46 ++--- be1-go/internal/handler/high/root_test.go | 10 +- 12 files changed, 310 insertions(+), 310 deletions(-) diff --git a/be1-go/internal/handler/high/channel.go b/be1-go/internal/handler/high/channel.go index 52f9ee2cd6..0989e5981b 100644 --- a/be1-go/internal/handler/high/channel.go +++ b/be1-go/internal/handler/high/channel.go @@ -46,7 +46,7 @@ func HandleChannel(channelPath string, msg message.Message, fromRumor bool) *ans channelType, err := db.GetChannelType(channelPath) if err != nil { - errAnswer := answer.NewQueryDatabaseError("channel type: %v", err) + errAnswer := answer.NewQueryDatabaseError("channelPath type: %v", err) return errAnswer.Wrap("HandleChannel") } @@ -66,7 +66,7 @@ func HandleChannel(channelPath string, msg message.Message, fromRumor bool) *ans case sqlite.FederationType: errAnswer = handleChannelFederation(channelPath, msg) default: - errAnswer = answer.NewInvalidResourceError("unknown channel type for %s", channelPath) + errAnswer = answer.NewInvalidResourceError("unknown channelPath type for %s", channelPath) } if errAnswer != nil { diff --git a/be1-go/internal/handler/high/channel_test.go b/be1-go/internal/handler/high/channel_test.go index ee24fce3a4..c8e8aa23cb 100644 --- a/be1-go/internal/handler/high/channel_test.go +++ b/be1-go/internal/handler/high/channel_test.go @@ -45,43 +45,43 @@ func Test_handleChannel(t *testing.T) { sender := base64.URLEncoding.EncodeToString(keypair.PublicBuf) type input struct { - name string - channel string - message message.Message - contains string + name string + channelPath string + message message.Message + contains string } args := make([]input, 0) - // Test 1: failed to handled message because unknown channel type + // Test 1: failed to handled message because unknown channelPath type - channel := "unknown" + channelPath := "unknown" msg := generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID).Return(false, nil) - mockRepository.On("GetChannelType", channel).Return("", nil) + mockRepository.On("GetChannelType", channelPath).Return("", nil) args = append(args, input{ - name: "Test 1", - channel: channel, - message: msg, - contains: "unknown channel type for " + channel, + name: "Test 1", + channelPath: channelPath, + message: msg, + contains: "unknown channelPath type for " + channelPath, }) - // Test 2: failed to handled message because db is disconnected when querying the channel type + // Test 2: failed to handled message because db is disconnected when querying the channelPath type - channel = "disconnectedDB" + channelPath = "disconnectedDB" msg = generator.NewChirpAddMsg(t, sender, keypair.Private, time.Now().Unix()) mockRepository.On("HasMessage", msg.MessageID).Return(false, nil) - mockRepository.On("GetChannelType", channel). + mockRepository.On("GetChannelType", channelPath). Return("", xerrors.Errorf("DB is disconnected")) args = append(args, input{ - name: "Test 2", - channel: channel, - message: msg, - contains: "DB is disconnected", + name: "Test 2", + channelPath: channelPath, + message: msg, + contains: "DB is disconnected", }) // Test 3: failed to handled message because message already exists @@ -189,7 +189,7 @@ func Test_handleChannel(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := HandleChannel(arg.channel, arg.message, false) + errAnswer := HandleChannel(arg.channelPath, arg.message, false) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) }) diff --git a/be1-go/internal/handler/high/chirp.go b/be1-go/internal/handler/high/chirp.go index c5ebaafb63..ad76840f3c 100644 --- a/be1-go/internal/handler/high/chirp.go +++ b/be1-go/internal/handler/high/chirp.go @@ -36,7 +36,7 @@ func handleChannelChirp(channelPath string, msg message.Message) *answer.Error { generalChirpsChannelID, ok := strings.CutSuffix(channelPath, Social+"/"+msg.Sender) if !ok { - errAnswer := answer.NewInvalidMessageFieldError("invalid channel path %s", channelPath) + errAnswer := answer.NewInvalidMessageFieldError("invalid channelPath path %s", channelPath) return errAnswer.Wrap("handleChannelChirp") } @@ -117,7 +117,7 @@ func verifyChirpMessage(channelID string, msg message.Message, chirpMsg messaged } if !strings.HasSuffix(channelID, msg.Sender) { - errAnswer := answer.NewAccessDeniedError("only the owner of the channel can post chirps") + errAnswer := answer.NewAccessDeniedError("only the owner of the channelPath can post chirps") return errAnswer.Wrap("verifyChirpMessage") } diff --git a/be1-go/internal/handler/high/chirp_test.go b/be1-go/internal/handler/high/chirp_test.go index 2dc7e52677..4d34409740 100644 --- a/be1-go/internal/handler/high/chirp_test.go +++ b/be1-go/internal/handler/high/chirp_test.go @@ -48,81 +48,81 @@ func Test_handleChannelChirp(t *testing.T) { // Test 1: successfully add a chirp and notify it - channelID := "/root/lao1/social/" + sender + channelPath := "/root/lao1/social/" + sender args = append(args, input{ - name: "Test 1", - channel: channelID, - msg: newChirpAddMsg(t, channelID, sender, time.Now().Unix(), mockRepository, false), - isError: false, - contains: "", + name: "Test 1", + channelPath: channelPath, + msg: newChirpAddMsg(t, channelPath, sender, time.Now().Unix(), mockRepository, false), + isError: false, + contains: "", }) - // Test 2: failed to add chirp because not owner of the channel + // Test 2: failed to add chirp because not owner of the channelPath - channelID = "/root/lao2/social/" + sender + channelPath = "/root/lao2/social/" + sender args = append(args, input{ - name: "Test 2", - channel: channelID, - msg: newChirpAddMsg(t, channelID, wrongSender, time.Now().Unix(), mockRepository, true), - isError: true, - contains: "only the owner of the channel can post chirps", + name: "Test 2", + channelPath: channelPath, + msg: newChirpAddMsg(t, channelPath, wrongSender, time.Now().Unix(), mockRepository, true), + isError: true, + contains: "only the owner of the channelPath can post chirps", }) // Test 3: failed to add chirp because negative timestamp - channelID = "/root/lao3/social/" + sender + channelPath = "/root/lao3/social/" + sender args = append(args, input{ - name: "Test 3", - channel: channelID, - msg: newChirpAddMsg(t, channelID, sender, -1, mockRepository, true), - isError: true, - contains: "invalid message field", + name: "Test 3", + channelPath: channelPath, + msg: newChirpAddMsg(t, channelPath, sender, -1, mockRepository, true), + isError: true, + contains: "invalid message field", }) // Test 4: successfully delete a chirp and notify it - channelID = "/root/lao4/social/" + sender + channelPath = "/root/lao4/social/" + sender args = append(args, input{ - name: "Test 4", - channel: channelID, - msg: newChirpDeleteMsg(t, channelID, sender, chirpID, time.Now().Unix(), mockRepository, false), - isError: false, - contains: "", + name: "Test 4", + channelPath: channelPath, + msg: newChirpDeleteMsg(t, channelPath, sender, chirpID, time.Now().Unix(), mockRepository, false), + isError: false, + contains: "", }) - // Test 5: failed to delete chirp because not owner of the channel + // Test 5: failed to delete chirp because not owner of the channelPath - channelID = "/root/lao5/social/" + sender + channelPath = "/root/lao5/social/" + sender args = append(args, input{ - name: "Test 5", - channel: channelID, - msg: newChirpDeleteMsg(t, channelID, wrongSender, chirpID, time.Now().Unix(), mockRepository, true), - isError: true, - contains: "only the owner of the channel can post chirps", + name: "Test 5", + channelPath: channelPath, + msg: newChirpDeleteMsg(t, channelPath, wrongSender, chirpID, time.Now().Unix(), mockRepository, true), + isError: true, + contains: "only the owner of the channelPath can post chirps", }) // Test 6: failed to delete chirp because negative timestamp - channelID = "/root/lao6/social/" + sender + channelPath = "/root/lao6/social/" + sender args = append(args, input{ - name: "Test 6", - channel: channelID, - msg: newChirpDeleteMsg(t, channelID, sender, chirpID, -1, mockRepository, true), - isError: true, - contains: "invalid message field", + name: "Test 6", + channelPath: channelPath, + msg: newChirpDeleteMsg(t, channelPath, sender, chirpID, -1, mockRepository, true), + isError: true, + contains: "invalid message field", }) // Tests all cases for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannelChirp(arg.channel, arg.msg) + errAnswer := handleChannelChirp(arg.channelPath, arg.msg) if arg.isError { require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) diff --git a/be1-go/internal/handler/high/coin_test.go b/be1-go/internal/handler/high/coin_test.go index 243728460e..98a641b081 100644 --- a/be1-go/internal/handler/high/coin_test.go +++ b/be1-go/internal/handler/high/coin_test.go @@ -39,52 +39,52 @@ func Test_handleChannelCoin(t *testing.T) { inputs := make([]inputTestHandleChannelCoin, 0) - // Tests that the channel works correctly when it receives a transaction + // Tests that the channelPath works correctly when it receives a transaction inputs = append(inputs, newSuccessTestHandleChannelCoin(t, "post_transaction.json", "send transaction", mockRepository)) - // Tests that the channel works correctly when it receives a large transaction + // Tests that the channelPath works correctly when it receives a large transaction inputs = append(inputs, newSuccessTestHandleChannelCoin(t, "post_transaction_max_amount.json", "send transaction max amount", mockRepository)) - // Tests that the channel rejects transactions that exceed the maximum amount + // Tests that the channelPath rejects transactions that exceed the maximum amount inputs = append(inputs, newFailTestHandleChannelCoin(t, "post_transaction_overflow_amount.json", "send transaction overflow amount")) - // Tests that the channel accepts transactions with zero amounts + // Tests that the channelPath accepts transactions with zero amounts inputs = append(inputs, newSuccessTestHandleChannelCoin(t, "post_transaction_zero_amount.json", "send transaction zero amount", mockRepository)) - // Tests that the channel rejects transactions with negative amounts + // Tests that the channelPath rejects transactions with negative amounts inputs = append(inputs, newFailTestHandleChannelCoin(t, "post_transaction_negative_amount.json", "send transaction negative amount")) - // Tests that the channel rejects Transaction with wrong id + // Tests that the channelPath rejects Transaction with wrong id inputs = append(inputs, newFailTestHandleChannelCoin(t, "post_transaction_wrong_transaction_id.json", "send transaction wrong id")) - // Tests that the channel rejects Transaction with bad signature + // Tests that the channelPath rejects Transaction with bad signature inputs = append(inputs, newFailTestHandleChannelCoin(t, "post_transaction_bad_signature.json", "send transaction bad signature")) - // Tests that the channel works correctly when it receives a transaction + // Tests that the channelPath works correctly when it receives a transaction inputs = append(inputs, newSuccessTestHandleChannelCoin(t, "post_transaction_coinbase.json", diff --git a/be1-go/internal/handler/high/election_test.go b/be1-go/internal/handler/high/election_test.go index 1cf80cfcfb..047921a11d 100644 --- a/be1-go/internal/handler/high/election_test.go +++ b/be1-go/internal/handler/high/election_test.go @@ -52,9 +52,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 1", msg: newElectionOpenMsg(t, ownerPublicKey, wrongSender, laoID, electionID, channelPath, "", -1, true, mockRepository), - channel: channelPath, - isError: true, - contains: "sender is not the organizer of the channel", + channelPath: channelPath, + isError: true, + contains: "sender is not the organizer of the channel", }) wrongChannelPath := "/root/" + base64.URLEncoding.EncodeToString([]byte("wrongLaoID")) + "/" + electionID @@ -64,9 +64,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 2", msg: newElectionOpenMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", -1, true, mockRepository), - channel: wrongChannelPath, - isError: true, - contains: "lao id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "lao id is not the same as the channel", }) wrongChannelPath = "/root/" + laoID + "/" + base64.URLEncoding.EncodeToString([]byte("wrongElectionID")) @@ -76,9 +76,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 3", msg: newElectionOpenMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", -1, true, mockRepository), - channel: wrongChannelPath, - isError: true, - contains: "election id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "election id is not the same as the channel", }) // Test 4 Error when Election is already started or ended @@ -86,9 +86,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 4", msg: newElectionOpenMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionOpen, -1, true, mockRepository), - channel: channelPath, - isError: true, - contains: "election is already started or ended", + channelPath: channelPath, + isError: true, + contains: "election is already started or ended", }) //to avoid conflicts with the previous test @@ -99,9 +99,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 5", msg: newElectionOpenMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionSetup, 2, true, mockRepository), - channel: channelPath, - isError: true, - contains: "election open cannot have a creation time prior to election setup", + channelPath: channelPath, + isError: true, + contains: "election open cannot have a creation time prior to election setup", }) //to avoid conflicts with the previous test @@ -116,9 +116,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 6", msg: newElectionOpenMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionSetup, 1, false, mockRepository), - channel: channelPath, - isError: false, - contains: "", + channelPath: channelPath, + isError: false, + contains: "", }) laoID = base64.URLEncoding.EncodeToString([]byte("electionID4")) @@ -129,9 +129,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 7", msg: newElectionEndMsg(t, ownerPublicKey, wrongSender, laoID, electionID, channelPath, "", "", -1, true, mockRepository), - channel: channelPath, - isError: true, - contains: "sender is not the organizer of the channel", + channelPath: channelPath, + isError: true, + contains: "sender is not the organizer of the channel", }) wrongChannelPath = "/root/" + base64.URLEncoding.EncodeToString([]byte("wrongLaoID2")) + "/" + electionID @@ -141,9 +141,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 8", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", "", -1, true, mockRepository), - channel: wrongChannelPath, - isError: true, - contains: "lao id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "lao id is not the same as the channel", }) wrongChannelPath = "/root/" + laoID + "/" + base64.URLEncoding.EncodeToString([]byte("wrongElectionID2")) @@ -153,9 +153,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 9", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", "", -1, true, mockRepository), - channel: wrongChannelPath, - isError: true, - contains: "election id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "election id is not the same as the channel", }) // Test 10 Error when ElectionEnd is not started @@ -163,9 +163,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 10", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionEnd, "", -1, true, mockRepository), - channel: channelPath, - isError: true, - contains: "election was not started", + channelPath: channelPath, + isError: true, + contains: "election was not started", }) //to avoid conflicts with the previous test @@ -177,9 +177,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 11", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionOpen, "", 2, true, mockRepository), - channel: channelPath, - isError: true, - contains: "election end cannot have a creation time prior to election setup", + channelPath: channelPath, + isError: true, + contains: "election end cannot have a creation time prior to election setup", }) //to avoid conflicts with the previous test @@ -193,9 +193,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 12", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionOpen, wrongVotes, 1, true, mockRepository), - channel: channelPath, - isError: true, - contains: fmt.Sprintf("registered votes is %s, should be sorted and equal to", wrongVotes), + channelPath: channelPath, + isError: true, + contains: fmt.Sprintf("registered votes is %s, should be sorted and equal to", wrongVotes), }) //to avoid conflicts with the previous test @@ -212,9 +212,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 13", msg: newElectionEndMsg(t, ownerPublicKey, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionOpen, registeredVotes, 1, false, mockRepository), - channel: channelPath, - isError: false, - contains: "", + channelPath: channelPath, + isError: false, + contains: "", }) votes := []generator.VoteInt{ @@ -230,9 +230,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 14", msg: newVoteCastVoteIntMsg(t, wrongSender, laoID, electionID, channelPath, "", "", -1, votes, nil, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: true, - contains: "sender is not an attendee or the organizer of the election", + channelPath: channelPath, + isError: true, + contains: "sender is not an attendee or the organizer of the election", }) // Test 15 Error when VoteCastVote lao id is not the same as the channel @@ -242,9 +242,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 15", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", "", -1, votes, nil, ownerPublicKey, mockRepository, true), - channel: wrongChannelPath, - isError: true, - contains: "lao id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "lao id is not the same as the channel", }) // Test 16 Error when VoteCastVote election id is not the same as the channel @@ -254,9 +254,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 16", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, wrongChannelPath, "", "", -1, votes, nil, ownerPublicKey, mockRepository, true), - channel: wrongChannelPath, - isError: true, - contains: "election id is not the same as the channel", + channelPath: wrongChannelPath, + isError: true, + contains: "election id is not the same as the channel", }) //to avoid conflicts with the previous test @@ -268,9 +268,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 17", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, "", "", 2, votes, nil, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: true, - contains: "cast vote cannot have a creation time prior to election setup", + channelPath: channelPath, + isError: true, + contains: "cast vote cannot have a creation time prior to election setup", }) //to avoid conflicts with the previous test @@ -287,9 +287,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 18", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, "", "", 0, votes, questions, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: true, - contains: "Question does not exist", + channelPath: channelPath, + isError: true, + contains: "Question does not exist", }) //to avoid conflicts with the previous test @@ -309,9 +309,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 19", msg: newVoteCastVoteStringMsg(t, ownerPubBuf64, laoID, electionID, channelPath, messagedata.OpenBallot, 0, stringVotes, questions, ownerPublicKey, mockRepository), - channel: channelPath, - isError: true, - contains: "vote in open ballot should be an integer", + channelPath: channelPath, + isError: true, + contains: "vote in open ballot should be an integer", }) //to avoid conflicts with the previous test @@ -331,9 +331,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 20", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, "", messagedata.SecretBallot, 0, intVotes, questions, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: true, - contains: "vote in secret ballot should be a string", + channelPath: channelPath, + isError: true, + contains: "vote in secret ballot should be a string", }) //to avoid conflicts with the previous test @@ -346,9 +346,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 21", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, "", messagedata.OpenBallot, 0, intVotes, questions, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: true, - contains: "vote ID is not the expected hash", + channelPath: channelPath, + isError: true, + contains: "vote ID is not the expected hash", }) //to avoid conflicts with the previous test @@ -374,9 +374,9 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 22", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionEnd, messagedata.OpenBallot, 0, votes, questions, ownerPublicKey, mockRepository, false), - channel: channelPath, - isError: false, - contains: "", + channelPath: channelPath, + isError: false, + contains: "", }) //to avoid conflicts with the previous test @@ -388,14 +388,14 @@ func Test_handleChannelElection(t *testing.T) { name: "Test 23", msg: newVoteCastVoteIntMsg(t, ownerPubBuf64, laoID, electionID, channelPath, messagedata.ElectionActionOpen, "", -1, votes, nil, ownerPublicKey, mockRepository, true), - channel: channelPath, - isError: false, - contains: "", + channelPath: channelPath, + isError: false, + contains: "", }) for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannelElection(arg.channel, arg.msg) + errAnswer := handleChannelElection(arg.channelPath, arg.msg) if arg.isError { require.Contains(t, errAnswer.Error(), arg.contains) } else { diff --git a/be1-go/internal/handler/high/federation.go b/be1-go/internal/handler/high/federation.go index f4429e42b9..fabcf06b11 100644 --- a/be1-go/internal/handler/high/federation.go +++ b/be1-go/internal/handler/high/federation.go @@ -18,7 +18,7 @@ import ( "popstellar/internal/message/query/method/message" "popstellar/internal/network/socket" "popstellar/internal/singleton/database" - state2 "popstellar/internal/singleton/state" + state "popstellar/internal/singleton/state" "strings" "time" ) @@ -62,7 +62,7 @@ func handleChannelFederation(channelPath string, msg message.Message) *answer.Er } // handleRequestChallenge expects the sender to be the organizer of the lao, -// a challenge message is then stored and broadcast on the same channel. +// a challenge message is then stored and broadcast on the same channelPath. // The FederationChallengeRequest message is neither stored nor broadcast func handleRequestChallenge(msg message.Message, channelPath string) *answer.Error { var requestChallenge messagedata.FederationChallengeRequest @@ -169,7 +169,7 @@ func handleExpect(msg message.Message, channelPath string) *answer.Error { } remoteChannel := fmt.Sprintf(channelPattern, federationExpect.LaoId) - _ = state2.AddChannel(remoteChannel) + _ = state.AddChannel(remoteChannel) err = db.StoreMessageAndData(channelPath, msg) if err != nil { @@ -231,8 +231,8 @@ func handleInit(msg message.Message, channelPath string) *answer.Error { //Force the remote server to be subscribed to /root//federation remoteChannel := fmt.Sprintf(channelPattern, federationInit.LaoId) - _ = state2.AddChannel(remoteChannel) - errAnswer = state2.Subscribe(remote, remoteChannel) + _ = state.AddChannel(remoteChannel) + errAnswer = state.Subscribe(remote, remoteChannel) if errAnswer != nil { return errAnswer.Wrap("handleFederationInit") } @@ -255,12 +255,12 @@ func handleInit(msg message.Message, channelPath string) *answer.Error { } // Subscribe to /root//federation on the remote server - errAnswer = state2.SendToAll(subscribeBytes, remoteChannel) + errAnswer = state.SendToAll(subscribeBytes, remoteChannel) if errAnswer != nil { return errAnswer.Wrap("handleFederationInit") } - // send the challenge to a channel where the remote server is subscribed to + // send the challenge to a channelPath where the remote server is subscribed to errAnswer = publishTo(federationInit.ChallengeMsg, remoteChannel) if errAnswer != nil { return errAnswer.Wrap("handleFederationInit") @@ -468,7 +468,7 @@ func verifyLocalOrganizer(msg message.Message, channelPath string) *answer.Error } if organizePk != msg.Sender { - errAnswer = answer.NewAccessDeniedError("sender is not the organizer of the channel") + errAnswer = answer.NewAccessDeniedError("sender is not the organizer of the channelPath") return errAnswer.Wrap("verifyLocalSender") } @@ -483,22 +483,22 @@ func connectTo(serverAddress string) (socket.Socket, *answer.Error) { return nil, errAnswer.Wrap("connectTo") } - messageChan, errAnswer := state2.GetMessageChan() + messageChan, errAnswer := state.GetMessageChan() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - closedSockets, errAnswer := state2.GetClosedSockets() + closedSockets, errAnswer := state.GetClosedSockets() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - wg, errAnswer := state2.GetWaitGroup() + wg, errAnswer := state.GetWaitGroup() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } - stopChan, errAnswer := state2.GetStopChan() + stopChan, errAnswer := state.GetStopChan() if errAnswer != nil { return nil, errAnswer.Wrap("connectTo") } @@ -562,7 +562,7 @@ func createMessage(data messagedata.MessageData) (message.Message, *answer.Error return msg, nil } -func publishTo(msg message.Message, channel string) *answer.Error { +func publishTo(msg message.Message, channelPath string) *answer.Error { publishMsg := method.Publish{ Base: query.Base{ JSONRPCBase: jsonrpc.JSONRPCBase{ @@ -571,7 +571,7 @@ func publishTo(msg message.Message, channel string) *answer.Error { Method: "publish", }, Params: method.PublishParams{ - Channel: channel, + Channel: channelPath, Message: msg, }, } @@ -583,7 +583,7 @@ func publishTo(msg message.Message, channel string) *answer.Error { return errAnswer.Wrap("publishTo") } - errAnswer := state2.SendToAll(publishBytes, channel) + errAnswer := state.SendToAll(publishBytes, channelPath) if errAnswer != nil { return errAnswer.Wrap("publishTo") } diff --git a/be1-go/internal/handler/high/federation_test.go b/be1-go/internal/handler/high/federation_test.go index 56ef993bc1..68991822a6 100644 --- a/be1-go/internal/handler/high/federation_test.go +++ b/be1-go/internal/handler/high/federation_test.go @@ -68,18 +68,18 @@ func Test_handleChannelFederation(t *testing.T) { // Test 1 Error when FederationChallengeRequest sender is not the same as // the lao organizer args = append(args, input{ - name: "Test 1", - channel: channelPath, + name: "Test 1", + channelPath: channelPath, msg: generator.NewFederationChallengeRequest(t, notOrganizer, validUntil, notOrganizerSk), isError: true, - contains: "sender is not the organizer of the channel", + contains: "sender is not the organizer of the channelPath", }) // Test 2 Error when FederationChallengeRequest timestamp is negative args = append(args, input{ - name: "Test 2", - channel: channelPath, + name: "Test 2", + channelPath: channelPath, msg: generator.NewFederationChallengeRequest(t, organizer, -1, organizerSk), isError: true, @@ -89,21 +89,21 @@ func Test_handleChannelFederation(t *testing.T) { // Test 3 Error when FederationExpect sender is not the same as the lao // organizer args = append(args, input{ - name: "Test 3", - channel: channelPath, + name: "Test 3", + channelPath: channelPath, msg: generator.NewFederationExpect(t, notOrganizer, laoID, serverAddressA, organizer2, generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), notOrganizerSk), isError: true, - contains: "sender is not the organizer of the channel", + contains: "sender is not the organizer of the channelPath", }) // Test 4 Error when FederationExpect serverAddress is not valid format args = append(args, input{ - name: "Test 4", - channel: channelPath, + name: "Test 4", + channelPath: channelPath, msg: generator.NewFederationExpect(t, organizer, laoID, "ws:localhost:12345/client", organizer2, generator.NewFederationChallenge(t, organizer, @@ -115,8 +115,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 5 Error when FederationExpect publicKey is not valid format args = append(args, input{ - name: "Test 5", - channel: channelPath, + name: "Test 5", + channelPath: channelPath, msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, "organizer2", generator.NewFederationChallenge(t, organizer, @@ -128,8 +128,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 6 Error when FederationExpect laoId is not valid format args = append(args, input{ - name: "Test 6", - channel: channelPath, + name: "Test 6", + channelPath: channelPath, msg: generator.NewFederationExpect(t, organizer, "laoID", serverAddressA, organizer2, generator.NewFederationChallenge(t, organizer, @@ -141,8 +141,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 7 Error when FederationExpect challenge message is not a challenge args = append(args, input{ - name: "Test 7", - channel: channelPath, + name: "Test 7", + channelPath: channelPath, msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, organizer2, generator.NewFederationChallengeRequest(t, organizer, @@ -154,35 +154,35 @@ func Test_handleChannelFederation(t *testing.T) { // Test 8 Error when FederationExpect challenge is not from organizer args = append(args, input{ - name: "Test 8", - channel: channelPath, + name: "Test 8", + channelPath: channelPath, msg: generator.NewFederationExpect(t, organizer, laoID, serverAddressA, organizer2, generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), organizerSk), isError: true, - contains: "sender is not the organizer of the channel", + contains: "sender is not the organizer of the channelPath", }) // Test 9 Error when FederationInit sender is not the same as the lao // organizer args = append(args, input{ - name: "Test 9", - channel: channelPath, + name: "Test 9", + channelPath: channelPath, msg: generator.NewFederationInit(t, notOrganizer, laoID, serverAddressA, organizer2, generator.NewFederationChallenge(t, organizer, value, validUntil, organizerSk), notOrganizerSk), isError: true, - contains: "sender is not the organizer of the channel", + contains: "sender is not the organizer of the channelPath", }) // Test 10 Error when FederationInit serverAddress is not valid format args = append(args, input{ - name: "Test 10", - channel: channelPath, + name: "Test 10", + channelPath: channelPath, msg: generator.NewFederationInit(t, organizer, laoID, "ws:localhost:12345/client", organizer2, generator.NewFederationChallenge(t, organizer, @@ -194,8 +194,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 11 Error when FederationInit publicKey is not valid format args = append(args, input{ - name: "Test 11", - channel: channelPath, + name: "Test 11", + channelPath: channelPath, msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, "organizer2", generator.NewFederationChallenge(t, organizer, @@ -207,8 +207,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 12 Error when FederationInit laoId is not valid format args = append(args, input{ - name: "Test 12", - channel: channelPath, + name: "Test 12", + channelPath: channelPath, msg: generator.NewFederationInit(t, organizer, "laoID", serverAddressA, organizer2, generator.NewFederationChallenge(t, organizer, @@ -220,8 +220,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 13 Error when FederationInit challenge message is not a challenge args = append(args, input{ - name: "Test 13", - channel: channelPath, + name: "Test 13", + channelPath: channelPath, msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, organizer2, generator.NewFederationChallengeRequest(t, organizer, @@ -233,15 +233,15 @@ func Test_handleChannelFederation(t *testing.T) { // Test 14 Error when FederationInit challenge is not from organizer args = append(args, input{ - name: "Test 14", - channel: channelPath, + name: "Test 14", + channelPath: channelPath, msg: generator.NewFederationInit(t, organizer, laoID, serverAddressA, organizer2, generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), organizerSk), isError: true, - contains: "sender is not the organizer of the channel", + contains: "sender is not the organizer of the channelPath", }) federationChallenge1 := messagedata.FederationChallenge{ @@ -258,8 +258,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 15 Error when FederationChallenge is received without any // matching FederationExpect args = append(args, input{ - name: "Test 15", - channel: channelPath, + name: "Test 15", + channelPath: channelPath, msg: generator.NewFederationChallenge(t, notOrganizer, value, validUntil, notOrganizerSk), isError: true, @@ -268,8 +268,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 16 Error when FederationResult challenge message is not a challenge args = append(args, input{ - name: "Test 16", - channel: channelPath, + name: "Test 16", + channelPath: channelPath, msg: generator.NewSuccessFederationResult(t, organizer2, organizer, generator.NewFederationChallengeRequest(t, organizer2, validUntil, organizer2Sk), organizer2Sk), @@ -279,8 +279,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 17 Error when FederationResult PublicKey is not the organizerPk args = append(args, input{ - name: "Test 17", - channel: channelPath, + name: "Test 17", + channelPath: channelPath, msg: generator.NewSuccessFederationResult(t, organizer2, notOrganizer, generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk), organizer2Sk), @@ -295,8 +295,8 @@ func Test_handleChannelFederation(t *testing.T) { // Test 18 Error when FederationResult is received without any // matching FederationInit args = append(args, input{ - name: "Test 18", - channel: channelPath, + name: "Test 18", + channelPath: channelPath, msg: generator.NewSuccessFederationResult(t, organizer2, organizer, generator.NewFederationChallenge(t, organizer2, value, validUntil, organizer2Sk), organizer2Sk), @@ -306,7 +306,7 @@ func Test_handleChannelFederation(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannelFederation(arg.channel, arg.msg) + errAnswer := handleChannelFederation(arg.channelPath, arg.msg) if arg.isError { require.Contains(t, errAnswer.Error(), arg.contains) } else { diff --git a/be1-go/internal/handler/high/lao_test.go b/be1-go/internal/handler/high/lao_test.go index d1bc8949d6..41f3c381eb 100644 --- a/be1-go/internal/handler/high/lao_test.go +++ b/be1-go/internal/handler/high/lao_test.go @@ -50,11 +50,11 @@ func Test_handleChannelLao(t *testing.T) { // Test 1:Success For LaoState message args = append(args, input{ - name: "Test 1", - msg: newLaoStateMsg(t, ownerPubBuf64, laoID, mockRepository), - channel: laoID, - isError: false, - contains: "", + name: "Test 1", + msg: newLaoStateMsg(t, ownerPubBuf64, laoID, mockRepository), + channelPath: laoID, + isError: false, + contains: "", }) creation := time.Now().Unix() @@ -63,38 +63,38 @@ func Test_handleChannelLao(t *testing.T) { // Test 2: Error when RollCallCreate ID is not the expected hash args = append(args, input{ - name: "Test 2", - msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, wrongLaoName, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "roll call id is", + name: "Test 2", + msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, wrongLaoName, creation, start, end, true, mockRepository), + channelPath: laoID, + isError: true, + contains: "roll call id is", }) // Test 3: Error when RollCallCreate proposed start is before creation args = append(args, input{ - name: "Test 3", - msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, creation-1, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "roll call proposed start time should be greater than creation time", + name: "Test 3", + msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, creation-1, end, true, mockRepository), + channelPath: laoID, + isError: true, + contains: "roll call proposed start time should be greater than creation time", }) // Test 4: Error when RollCallCreate proposed end is before proposed start args = append(args, input{ - name: "Test 4", - msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, start, start-1, true, mockRepository), - channel: laoID, - isError: true, - contains: "roll call proposed end should be greater than proposed start", + name: "Test 4", + msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, start, start-1, true, mockRepository), + channelPath: laoID, + isError: true, + contains: "roll call proposed end should be greater than proposed start", }) // Test 5: Success for RollCallCreate message args = append(args, input{ - name: "Test 5", - msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, start, end, false, mockRepository), - channel: laoID, - isError: false, - contains: "", + name: "Test 5", + msg: newRollCallCreateMsg(t, ownerPubBuf64, laoID, goodLaoName, creation, start, end, false, mockRepository), + channelPath: laoID, + isError: false, + contains: "", }) opens := base64.URLEncoding.EncodeToString([]byte("opens")) @@ -102,20 +102,20 @@ func Test_handleChannelLao(t *testing.T) { // Test 6: Error when RollCallOpen ID is not the expected hash args = append(args, input{ - name: "Test 6", - msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, wrongOpens, "", time.Now().Unix(), true, mockRepository), - channel: laoID, - isError: true, - contains: "roll call update id is", + name: "Test 6", + msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, wrongOpens, "", time.Now().Unix(), true, mockRepository), + channelPath: laoID, + isError: true, + contains: "roll call update id is", }) // Test 7: Error when RollCallOpen opens is not the same as previous RollCallCreate args = append(args, input{ - name: "Test 7", - msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, opens, wrongOpens, time.Now().Unix(), true, mockRepository), - channel: laoID, - isError: true, - contains: "previous id does not exist", + name: "Test 7", + msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, opens, wrongOpens, time.Now().Unix(), true, mockRepository), + channelPath: laoID, + isError: true, + contains: "previous id does not exist", }) laoID = base64.URLEncoding.EncodeToString([]byte("laoID2")) @@ -124,11 +124,11 @@ func Test_handleChannelLao(t *testing.T) { // Test 8: Success for RollCallOpen message args = append(args, input{ - name: "Test 8", - msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, opens, opens, time.Now().Unix(), false, mockRepository), - channel: laoID, - isError: false, - contains: "", + name: "Test 8", + msg: newRollCallOpenMsg(t, ownerPubBuf64, laoID, opens, opens, time.Now().Unix(), false, mockRepository), + channelPath: laoID, + isError: false, + contains: "", }) closes := base64.URLEncoding.EncodeToString([]byte("closes")) @@ -136,20 +136,20 @@ func Test_handleChannelLao(t *testing.T) { // Test 9: Error when RollCallClose ID is not the expected hash args = append(args, input{ - name: "Test 9", - msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, wrongCloses, "", time.Now().Unix(), true, mockRepository), - channel: laoID, - isError: true, - contains: "roll call update id is", + name: "Test 9", + msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, wrongCloses, "", time.Now().Unix(), true, mockRepository), + channelPath: laoID, + isError: true, + contains: "roll call update id is", }) // Test 10: Error when RollCallClose closes is not the same as previous RollCallOpen args = append(args, input{ - name: "Test 10", - msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, closes, wrongCloses, time.Now().Unix(), true, mockRepository), - channel: laoID, - isError: true, - contains: "previous id does not exist", + name: "Test 10", + msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, closes, wrongCloses, time.Now().Unix(), true, mockRepository), + channelPath: laoID, + isError: true, + contains: "previous id does not exist", }) laoID = base64.URLEncoding.EncodeToString([]byte("laoID3")) @@ -158,11 +158,11 @@ func Test_handleChannelLao(t *testing.T) { // Test 11: Success for RollCallClose message args = append(args, input{ - name: "Test 11", - msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, closes, closes, time.Now().Unix(), false, mockRepository), - channel: laoID, - isError: false, - contains: "", + name: "Test 11", + msg: newRollCallCloseMsg(t, ownerPubBuf64, laoID, closes, closes, time.Now().Unix(), false, mockRepository), + channelPath: laoID, + isError: false, + contains: "", }) electionsName := "electionName" @@ -173,20 +173,20 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 12", msg: newElectionSetupMsg(t, ownerPublicKey, wrongSender, laoID, laoID, electionsName, question, messagedata.OpenBallot, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "sender public key does not match organizer public key", + channelPath: laoID, + isError: true, + contains: "sender public key does not match organizer public key", }) wrongLaoID := base64.URLEncoding.EncodeToString([]byte("wrongLaoID")) - // Test 13: Error when ElectionSetup lao is not the same as the channel + // Test 13: Error when ElectionSetup lao is not the same as the channelPath args = append(args, input{ name: "Test 13", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, wrongLaoID, laoID, electionsName, question, messagedata.OpenBallot, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "lao id is", + channelPath: laoID, + isError: true, + contains: "lao id is", }) // Test 14: Error when ElectionSetup ID is not the expected hash @@ -194,9 +194,9 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 14", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, "wrongName", question, messagedata.OpenBallot, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "election id is", + channelPath: laoID, + isError: true, + contains: "election id is", }) // Test 15: Error when proposedStart is before createdAt @@ -204,9 +204,9 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 15", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, electionsName, question, messagedata.OpenBallot, creation, creation-1, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "election start should be greater that creation time", + channelPath: laoID, + isError: true, + contains: "election start should be greater that creation time", }) // Test 16: Error when proposedEnd is before proposedStart @@ -214,9 +214,9 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 16", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, electionsName, question, messagedata.OpenBallot, creation, start, start-1, true, mockRepository), - channel: laoID, - isError: true, - contains: "election end should be greater that start time", + channelPath: laoID, + isError: true, + contains: "election end should be greater that start time", }) // Test 17: Error when ElectionSetup question is empty @@ -224,9 +224,9 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 17", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, electionsName, "", messagedata.OpenBallot, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "Question is empty", + channelPath: laoID, + isError: true, + contains: "Question is empty", }) //Test 18: Error when question hash is not the same as the expected hash @@ -234,9 +234,9 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 18", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, electionsName, wrongQuestion, messagedata.OpenBallot, creation, start, end, true, mockRepository), - channel: laoID, - isError: true, - contains: "Question id is", + channelPath: laoID, + isError: true, + contains: "Question id is", }) laoID = base64.URLEncoding.EncodeToString([]byte("laoID4")) @@ -248,14 +248,14 @@ func Test_handleChannelLao(t *testing.T) { name: "Test 19", msg: newElectionSetupMsg(t, ownerPublicKey, ownerPubBuf64, laoID, laoID, electionsName, question, messagedata.OpenBallot, creation, start, end, false, mockRepository), - channel: laoID, - isError: false, - contains: "", + channelPath: laoID, + isError: false, + contains: "", }) for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannelLao(arg.channel, arg.msg) + errAnswer := handleChannelLao(arg.channelPath, arg.msg) if arg.isError { require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) diff --git a/be1-go/internal/handler/high/reaction.go b/be1-go/internal/handler/high/reaction.go index adeb5e8127..8e583efa69 100644 --- a/be1-go/internal/handler/high/reaction.go +++ b/be1-go/internal/handler/high/reaction.go @@ -8,7 +8,7 @@ import ( "strings" ) -func handleChannelReaction(channel string, msg message.Message) *answer.Error { +func handleChannelReaction(channelPath string, msg message.Message) *answer.Error { object, action, errAnswer := verifyDataAndGetObjectAction(msg) if errAnswer != nil { return errAnswer.Wrap("handleChannelReaction") @@ -19,7 +19,7 @@ func handleChannelReaction(channel string, msg message.Message) *answer.Error { return errAnswer.Wrap("handleChannelReaction") } - laoPath, _ := strings.CutSuffix(channel, Social+Reactions) + laoPath, _ := strings.CutSuffix(channelPath, Social+Reactions) isAttendee, err := db.IsAttendee(laoPath, msg.Sender) if err != nil { errAnswer := answer.NewQueryDatabaseError("if is attendee: %v", err) @@ -42,13 +42,13 @@ func handleChannelReaction(channel string, msg message.Message) *answer.Error { return errAnswer.Wrap("handleChannelReaction") } - err = db.StoreMessageAndData(channel, msg) + err = db.StoreMessageAndData(channelPath, msg) if err != nil { errAnswer := answer.NewStoreDatabaseError(err.Error()) return errAnswer.Wrap("handleChannelReaction") } - errAnswer = broadcastToAllClients(msg, channel) + errAnswer = broadcastToAllClients(msg, channelPath) if errAnswer != nil { return errAnswer.Wrap("handleChannelReaction") } diff --git a/be1-go/internal/handler/high/reaction_test.go b/be1-go/internal/handler/high/reaction_test.go index 0649f8f6f4..c23a47debd 100644 --- a/be1-go/internal/handler/high/reaction_test.go +++ b/be1-go/internal/handler/high/reaction_test.go @@ -52,8 +52,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID := RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 1", - channel: channelID, + name: "Test 1", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "👍", chirpID, time.Now().Unix(), mockRepository, false, false), isError: false, @@ -66,8 +66,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID = RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 2", - channel: channelID, + name: "Test 2", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "👎", chirpID, time.Now().Unix(), mockRepository, false, false), isError: false, @@ -80,8 +80,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID = RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 3", - channel: channelID, + name: "Test 3", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "❤️", chirpID, time.Now().Unix(), mockRepository, false, false), isError: false, @@ -94,8 +94,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID = RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 4", - channel: channelID, + name: "Test 4", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "👍", invalidChirpID, time.Now().Unix(), mockRepository, true, false), isError: true, @@ -108,8 +108,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID = RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 5", - channel: channelID, + name: "Test 5", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "👍", chirpID, -1, mockRepository, true, false), isError: true, @@ -122,8 +122,8 @@ func Test_handleChannelReaction(t *testing.T) { channelID = RootPrefix + laoID + Social + Reactions args = append(args, input{ - name: "Test 6", - channel: channelID, + name: "Test 6", + channelPath: channelID, msg: newReactionAddMsg(t, channelID, sender, "👍", chirpID, time.Now().Unix(), mockRepository, false, true), isError: true, @@ -137,8 +137,8 @@ func Test_handleChannelReaction(t *testing.T) { reactionID := "AAAAdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sK=" args = append(args, input{ - name: "Test 7", - channel: channelID, + name: "Test 7", + channelPath: channelID, msg: newReactionDeleteMsg(t, channelID, sender, reactionID, time.Now().Unix(), mockRepository, false, false, false, false), isError: false, @@ -152,8 +152,8 @@ func Test_handleChannelReaction(t *testing.T) { reactionID = "AAAAABu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sK=" args = append(args, input{ - name: "Test 8", - channel: channelID, + name: "Test 8", + channelPath: channelID, msg: newReactionDeleteMsg(t, channelID, sender, reactionID, -1, mockRepository, true, false, false, false), isError: true, @@ -167,8 +167,8 @@ func Test_handleChannelReaction(t *testing.T) { reactionID = "AAAAdBB8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sK=" args = append(args, input{ - name: "Test 9", - channel: channelID, + name: "Test 9", + channelPath: channelID, msg: newReactionDeleteMsg(t, channelID, sender, reactionID, time.Now().Unix(), mockRepository, false, true, false, false), isError: true, @@ -182,8 +182,8 @@ func Test_handleChannelReaction(t *testing.T) { reactionID = "AAAAdBB8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4KK=" args = append(args, input{ - name: "Test 10", - channel: channelID, + name: "Test 10", + channelPath: channelID, msg: newReactionDeleteMsg(t, channelID, sender, reactionID, time.Now().Unix(), mockRepository, false, false, true, false), isError: true, @@ -197,8 +197,8 @@ func Test_handleChannelReaction(t *testing.T) { reactionID = "AAAAdBB8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dRYKK=" args = append(args, input{ - name: "Test 11", - channel: channelID, + name: "Test 11", + channelPath: channelID, msg: newReactionDeleteMsg(t, channelID, sender, reactionID, time.Now().Unix(), mockRepository, false, false, false, true), isError: true, @@ -209,7 +209,7 @@ func Test_handleChannelReaction(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - errAnswer := handleChannelReaction(arg.channel, arg.msg) + errAnswer := handleChannelReaction(arg.channelPath, arg.msg) if arg.isError { require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) diff --git a/be1-go/internal/handler/high/root_test.go b/be1-go/internal/handler/high/root_test.go index d46379a4e9..a286f0a44c 100644 --- a/be1-go/internal/handler/high/root_test.go +++ b/be1-go/internal/handler/high/root_test.go @@ -27,11 +27,11 @@ const ( ) type input struct { - name string - channel string - msg message.Message - isError bool - contains string + name string + channelPath string + msg message.Message + isError bool + contains string } func Test_handleChannelRoot(t *testing.T) { From 048f5cc7473dd16f83d58192b93f5054742adb7f Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 17:07:18 +0200 Subject: [PATCH 12/19] rename high to channel --- be1-go/internal/handler/answer/answer.go | 4 ++-- be1-go/internal/handler/{high => channel}/channel.go | 2 +- be1-go/internal/handler/{high => channel}/channel_test.go | 2 +- be1-go/internal/handler/{high => channel}/chirp.go | 2 +- be1-go/internal/handler/{high => channel}/chirp_test.go | 2 +- be1-go/internal/handler/{high => channel}/coin.go | 2 +- be1-go/internal/handler/{high => channel}/coin_test.go | 2 +- be1-go/internal/handler/{high => channel}/election.go | 2 +- be1-go/internal/handler/{high => channel}/election_test.go | 2 +- be1-go/internal/handler/{high => channel}/federation.go | 2 +- .../internal/handler/{high => channel}/federation_test.go | 2 +- be1-go/internal/handler/{high => channel}/lao.go | 2 +- be1-go/internal/handler/{high => channel}/lao_test.go | 2 +- be1-go/internal/handler/{high => channel}/reaction.go | 2 +- be1-go/internal/handler/{high => channel}/reaction_test.go | 2 +- be1-go/internal/handler/{high => channel}/root.go | 2 +- be1-go/internal/handler/{high => channel}/root_test.go | 2 +- be1-go/internal/handler/query/publish.go | 4 ++-- be1-go/internal/handler/query/rumor.go | 6 +++--- be1-go/internal/handler/query/subscribe.go | 4 ++-- be1-go/internal/handler/query/unsubscribe.go | 4 ++-- 21 files changed, 27 insertions(+), 27 deletions(-) rename be1-go/internal/handler/{high => channel}/channel.go (99%) rename be1-go/internal/handler/{high => channel}/channel_test.go (99%) rename be1-go/internal/handler/{high => channel}/chirp.go (99%) rename be1-go/internal/handler/{high => channel}/chirp_test.go (99%) rename be1-go/internal/handler/{high => channel}/coin.go (99%) rename be1-go/internal/handler/{high => channel}/coin_test.go (99%) rename be1-go/internal/handler/{high => channel}/election.go (99%) rename be1-go/internal/handler/{high => channel}/election_test.go (99%) rename be1-go/internal/handler/{high => channel}/federation.go (99%) rename be1-go/internal/handler/{high => channel}/federation_test.go (99%) rename be1-go/internal/handler/{high => channel}/lao.go (99%) rename be1-go/internal/handler/{high => channel}/lao_test.go (99%) rename be1-go/internal/handler/{high => channel}/reaction.go (99%) rename be1-go/internal/handler/{high => channel}/reaction_test.go (99%) rename be1-go/internal/handler/{high => channel}/root.go (99%) rename be1-go/internal/handler/{high => channel}/root_test.go (99%) diff --git a/be1-go/internal/handler/answer/answer.go b/be1-go/internal/handler/answer/answer.go index df0c48dad7..411b34f501 100644 --- a/be1-go/internal/handler/answer/answer.go +++ b/be1-go/internal/handler/answer/answer.go @@ -3,7 +3,7 @@ package answer import ( "encoding/json" "math/rand" - "popstellar/internal/handler/high" + "popstellar/internal/handler/channel" "popstellar/internal/handler/query" "popstellar/internal/logger" "popstellar/internal/message/answer" @@ -146,7 +146,7 @@ func tryToHandleMessages(msgsByChannel map[string]map[string]message.Message, so for _, channelID := range sortedChannelIDs { msgs := msgsByChannel[channelID] for msgID, msg := range msgs { - errAnswer := high.HandleChannel(channelID, msg, false) + errAnswer := channel.HandleChannel(channelID, msg, false) if errAnswer == nil { delete(msgsByChannel[channelID], msgID) continue diff --git a/be1-go/internal/handler/high/channel.go b/be1-go/internal/handler/channel/channel.go similarity index 99% rename from be1-go/internal/handler/high/channel.go rename to be1-go/internal/handler/channel/channel.go index 0989e5981b..677320ca8b 100644 --- a/be1-go/internal/handler/high/channel.go +++ b/be1-go/internal/handler/channel/channel.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/channel_test.go b/be1-go/internal/handler/channel/channel_test.go similarity index 99% rename from be1-go/internal/handler/high/channel_test.go rename to be1-go/internal/handler/channel/channel_test.go index c8e8aa23cb..47792751b3 100644 --- a/be1-go/internal/handler/high/channel_test.go +++ b/be1-go/internal/handler/channel/channel_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/chirp.go b/be1-go/internal/handler/channel/chirp.go similarity index 99% rename from be1-go/internal/handler/high/chirp.go rename to be1-go/internal/handler/channel/chirp.go index ad76840f3c..0f35ed60ba 100644 --- a/be1-go/internal/handler/high/chirp.go +++ b/be1-go/internal/handler/channel/chirp.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/chirp_test.go b/be1-go/internal/handler/channel/chirp_test.go similarity index 99% rename from be1-go/internal/handler/high/chirp_test.go rename to be1-go/internal/handler/channel/chirp_test.go index 4d34409740..9e9f8779eb 100644 --- a/be1-go/internal/handler/high/chirp_test.go +++ b/be1-go/internal/handler/channel/chirp_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/coin.go b/be1-go/internal/handler/channel/coin.go similarity index 99% rename from be1-go/internal/handler/high/coin.go rename to be1-go/internal/handler/channel/coin.go index b80f791336..34fdf7c477 100644 --- a/be1-go/internal/handler/high/coin.go +++ b/be1-go/internal/handler/channel/coin.go @@ -1,4 +1,4 @@ -package high +package channel import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/handler/high/coin_test.go b/be1-go/internal/handler/channel/coin_test.go similarity index 99% rename from be1-go/internal/handler/high/coin_test.go rename to be1-go/internal/handler/channel/coin_test.go index 98a641b081..4197eb36d8 100644 --- a/be1-go/internal/handler/high/coin_test.go +++ b/be1-go/internal/handler/channel/coin_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/election.go b/be1-go/internal/handler/channel/election.go similarity index 99% rename from be1-go/internal/handler/high/election.go rename to be1-go/internal/handler/channel/election.go index 38d6da76b0..f7b305098c 100644 --- a/be1-go/internal/handler/high/election.go +++ b/be1-go/internal/handler/channel/election.go @@ -1,4 +1,4 @@ -package high +package channel import ( "bytes" diff --git a/be1-go/internal/handler/high/election_test.go b/be1-go/internal/handler/channel/election_test.go similarity index 99% rename from be1-go/internal/handler/high/election_test.go rename to be1-go/internal/handler/channel/election_test.go index 047921a11d..7e0de413ff 100644 --- a/be1-go/internal/handler/high/election_test.go +++ b/be1-go/internal/handler/channel/election_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/federation.go b/be1-go/internal/handler/channel/federation.go similarity index 99% rename from be1-go/internal/handler/high/federation.go rename to be1-go/internal/handler/channel/federation.go index fabcf06b11..2f923cba46 100644 --- a/be1-go/internal/handler/high/federation.go +++ b/be1-go/internal/handler/channel/federation.go @@ -1,4 +1,4 @@ -package high +package channel import ( "crypto/rand" diff --git a/be1-go/internal/handler/high/federation_test.go b/be1-go/internal/handler/channel/federation_test.go similarity index 99% rename from be1-go/internal/handler/high/federation_test.go rename to be1-go/internal/handler/channel/federation_test.go index 68991822a6..b8c7fc70b6 100644 --- a/be1-go/internal/handler/high/federation_test.go +++ b/be1-go/internal/handler/channel/federation_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "database/sql" diff --git a/be1-go/internal/handler/high/lao.go b/be1-go/internal/handler/channel/lao.go similarity index 99% rename from be1-go/internal/handler/high/lao.go rename to be1-go/internal/handler/channel/lao.go index 25583accda..34290c3da2 100644 --- a/be1-go/internal/handler/high/lao.go +++ b/be1-go/internal/handler/channel/lao.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/lao_test.go b/be1-go/internal/handler/channel/lao_test.go similarity index 99% rename from be1-go/internal/handler/high/lao_test.go rename to be1-go/internal/handler/channel/lao_test.go index 41f3c381eb..b4d0939c3b 100644 --- a/be1-go/internal/handler/high/lao_test.go +++ b/be1-go/internal/handler/channel/lao_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/reaction.go b/be1-go/internal/handler/channel/reaction.go similarity index 99% rename from be1-go/internal/handler/high/reaction.go rename to be1-go/internal/handler/channel/reaction.go index 8e583efa69..3a567d0296 100644 --- a/be1-go/internal/handler/high/reaction.go +++ b/be1-go/internal/handler/channel/reaction.go @@ -1,4 +1,4 @@ -package high +package channel import ( "popstellar/internal/message/answer" diff --git a/be1-go/internal/handler/high/reaction_test.go b/be1-go/internal/handler/channel/reaction_test.go similarity index 99% rename from be1-go/internal/handler/high/reaction_test.go rename to be1-go/internal/handler/channel/reaction_test.go index c23a47debd..11d83f84d7 100644 --- a/be1-go/internal/handler/high/reaction_test.go +++ b/be1-go/internal/handler/channel/reaction_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/root.go b/be1-go/internal/handler/channel/root.go similarity index 99% rename from be1-go/internal/handler/high/root.go rename to be1-go/internal/handler/channel/root.go index 907670dbe5..1852b726bb 100644 --- a/be1-go/internal/handler/high/root.go +++ b/be1-go/internal/handler/channel/root.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/high/root_test.go b/be1-go/internal/handler/channel/root_test.go similarity index 99% rename from be1-go/internal/handler/high/root_test.go rename to be1-go/internal/handler/channel/root_test.go index a286f0a44c..8a0c48d165 100644 --- a/be1-go/internal/handler/high/root_test.go +++ b/be1-go/internal/handler/channel/root_test.go @@ -1,4 +1,4 @@ -package high +package channel import ( "encoding/base64" diff --git a/be1-go/internal/handler/query/publish.go b/be1-go/internal/handler/query/publish.go index 4f3ecb0f5a..4ef2423924 100644 --- a/be1-go/internal/handler/query/publish.go +++ b/be1-go/internal/handler/query/publish.go @@ -2,7 +2,7 @@ package query import ( "encoding/json" - "popstellar/internal/handler/high" + "popstellar/internal/handler/channel" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" @@ -23,7 +23,7 @@ func handlePublish(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handlePublish") } - errAnswer := high.HandleChannel(publish.Params.Channel, publish.Params.Message, false) + errAnswer := channel.HandleChannel(publish.Params.Channel, publish.Params.Message, false) if errAnswer != nil { return &publish.ID, errAnswer.Wrap("handlePublish") } diff --git a/be1-go/internal/handler/query/rumor.go b/be1-go/internal/handler/query/rumor.go index 75ea802435..bf74d2b1e7 100644 --- a/be1-go/internal/handler/query/rumor.go +++ b/be1-go/internal/handler/query/rumor.go @@ -2,7 +2,7 @@ package query import ( "encoding/json" - "popstellar/internal/handler/high" + "popstellar/internal/handler/channel" "popstellar/internal/logger" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" @@ -89,13 +89,13 @@ func tryHandlingMessagesByChannel(unprocessedMsgsByChannel map[string][]message. return processedMsgs } -func tryHandlingMessages(channel string, unprocessedMsgs []message.Message) ([]message.Message, []string) { +func tryHandlingMessages(channelPath string, unprocessedMsgs []message.Message) ([]message.Message, []string) { processedMsgs := make([]string, 0) for i := 0; i < maxRetry; i++ { nbProcessed := 0 for index, msg := range unprocessedMsgs { - errAnswer := high.HandleChannel(channel, msg, true) + errAnswer := channel.HandleChannel(channelPath, msg, true) if errAnswer == nil { unprocessedMsgs = removeMessage(index-nbProcessed, unprocessedMsgs) processedMsgs = append(processedMsgs, msg.MessageID) diff --git a/be1-go/internal/handler/query/subscribe.go b/be1-go/internal/handler/query/subscribe.go index 1d6842fe28..eec6a4fe31 100644 --- a/be1-go/internal/handler/query/subscribe.go +++ b/be1-go/internal/handler/query/subscribe.go @@ -2,7 +2,7 @@ package query import ( "encoding/json" - "popstellar/internal/handler/high" + "popstellar/internal/handler/channel" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" "popstellar/internal/network/socket" @@ -18,7 +18,7 @@ func handleSubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handleSubscribe") } - if high.Root == subscribe.Params.Channel { + if channel.Root == subscribe.Params.Channel { errAnswer := answer.NewInvalidActionError("cannot Subscribe to root channel") return &subscribe.ID, errAnswer.Wrap("handleSubscribe") } diff --git a/be1-go/internal/handler/query/unsubscribe.go b/be1-go/internal/handler/query/unsubscribe.go index cb33f69183..2706e9e4c4 100644 --- a/be1-go/internal/handler/query/unsubscribe.go +++ b/be1-go/internal/handler/query/unsubscribe.go @@ -2,7 +2,7 @@ package query import ( "encoding/json" - "popstellar/internal/handler/high" + "popstellar/internal/handler/channel" "popstellar/internal/message/answer" "popstellar/internal/message/query/method" "popstellar/internal/network/socket" @@ -18,7 +18,7 @@ func handleUnsubscribe(socket socket.Socket, msg []byte) (*int, *answer.Error) { return nil, errAnswer.Wrap("handleUnsubscribe") } - if high.Root == unsubscribe.Params.Channel { + if channel.Root == unsubscribe.Params.Channel { errAnswer := answer.NewInvalidActionError("cannot Unsubscribe from root channel") return &unsubscribe.ID, errAnswer.Wrap("handleUnsubscribe") } From b9e101c8aaed4f563f2f607342665bd58d262d0e Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 17:44:04 +0200 Subject: [PATCH 13/19] update sonar conf --- be1-go/sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/be1-go/sonar-project.properties b/be1-go/sonar-project.properties index 0f9d4e6e5b..a824653c1c 100644 --- a/be1-go/sonar-project.properties +++ b/be1-go/sonar-project.properties @@ -7,7 +7,7 @@ sonar.go.coverage.reportPaths=./coverage.out # Path patterns of the source files sonar.sources=. -sonar.exclusions=**/*_test.go,**/test/**, **/generator/**, **/mock** +sonar.exclusions=**/*_test.go,**/test/**, **/mocks/** # Path patterns of the test files sonar.tests=. From 869873aeb41cdd819865eb8ab42df9fc6c859453 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 18:40:39 +0200 Subject: [PATCH 14/19] update the doc --- be1-go/docs/README.md | 45 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/be1-go/docs/README.md b/be1-go/docs/README.md index 293733194c..236d9da1a7 100644 --- a/be1-go/docs/README.md +++ b/be1-go/docs/README.md @@ -35,28 +35,33 @@ for their use. The project is organized into different modules as follows ``` -. -├── channel # contains the abstract definition of a channel NEED TO BE DELETED ├── cli # command line interface -├── crypto # defines the cryptographic suite ├── docs -├── hub # contains the abstract definition of a hub NEED TO BE DELETED -├── inbox # helper to store messages used by channels NEED TO BE DELETED -├── internal -│   ├── depgraph # tool to generate the dependencies graph -│   └── popserver # entry point of the messages received by the sockets -│   ├── config # singleton with the server config informations and server keys -│   ├── database # singleton with the database + implementations of the database -│   ├── generatortest # query and message generators only use for the tests -│   ├── handler # handlers for each query, answer and channel type (entry point is func HandleIncomingMessage) -│   ├── state # singleton with the temporary states of the server (peers, queries, and subscriptions) -│   ├── type # every types use in the implementation -│   └── utils # singleton with the log instance and the schema validator -├── message # message types and marshaling/unmarshaling logic -├── network # module to set up Websocket connections -│   └── socket # module to send/receive data over the wire -├── popcha # HTTP server and back-end logic for PoPCHA NEED TO BE REFACTOR -└── validation # module to validate incoming/outgoing messages +└── internal + ├── crypto # defines the cryptographic suite + ├── docsutils # utils use for the documentation + ├── handler # handle the incoming messages + │   ├── answer # handler for the answers + │   ├── channel # handler for the channel + │   └── query # handler for the queries + ├── hub # entry point of the messages received by the sockets + ├── logger # logger use inside the implementation + ├── message # message types and marshaling/unmarshaling logic + ├── mocks # mocks and utils use inside tests + │   └── generator # query and message generators only use for the tests + ├── network # module to set up Websocket connections + │   └── socket # module to send/receive data over the wire + ├── old # old implementation NEED TO BE DELETE + ├── popcha # HTTP server and back-end logic for PoPCHA NEED TO BE REFACTOR + ├── repository # repository for the database + ├── singleton # NEED TO BE REMOVE AND REPLACE BY REF INJECTION + │   ├── config # server config informations and server keys + │   ├── database # database + │   ├── state # temporary states of the server (peers, queries, and subscriptions) + │   └── utils # singleton with the log instance and the schema validator + ├── sqlite # sqlite implementation of the repository + ├── types # types use inside the implementation + └── validation # module to validate incoming/outgoing messages ``` The entry point is the `cli` with bulk of the implementation logic in the `popserver` package. From 994eeb79aa97a60c303a6962250cca1a043d5f13 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 18:41:57 +0200 Subject: [PATCH 15/19] update the doc --- be1-go/docs/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/be1-go/docs/README.md b/be1-go/docs/README.md index 236d9da1a7..222fc40231 100644 --- a/be1-go/docs/README.md +++ b/be1-go/docs/README.md @@ -35,15 +35,15 @@ for their use. The project is organized into different modules as follows ``` -├── cli # command line interface +├── cli # command line interface ├── docs └── internal ├── crypto # defines the cryptographic suite ├── docsutils # utils use for the documentation ├── handler # handle the incoming messages - │   ├── answer # handler for the answers - │   ├── channel # handler for the channel - │   └── query # handler for the queries + │   ├── answer # handler for the answers + │   ├── channel # handler for the channel + │   └── query # handler for the queries ├── hub # entry point of the messages received by the sockets ├── logger # logger use inside the implementation ├── message # message types and marshaling/unmarshaling logic From e8428b233677d25c55d335024e0faf9350a2bb5a Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 18:54:41 +0200 Subject: [PATCH 16/19] update the diagram dependencies --- .../docs/images/dependencies/dependencies.dot | 63 +++++++++++++----- .../docs/images/dependencies/dependencies.png | Bin 69017 -> 343282 bytes be1-go/internal/docsutils/depgraph/dep.yml | 8 ++- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/be1-go/docs/images/dependencies/dependencies.dot b/be1-go/docs/images/dependencies/dependencies.dot index b5e89a811c..d786dd2eaa 100644 --- a/be1-go/docs/images/dependencies/dependencies.dot +++ b/be1-go/docs/images/dependencies/dependencies.dot @@ -1,6 +1,6 @@ strict digraph { labelloc="t"; -label =
(generated 10 May 24 - 08:56:20)>; +label =
(generated 2 Jun 24 - 18:53:37)>; graph [fontname = "helvetica"]; graph [fontname = "helvetica"]; node [fontname = "helvetica"]; @@ -9,19 +9,50 @@ node [shape=box,style=rounded]; start=0; ratio = fill; rankdir="LR"; -"internal/popserver" -> "internal/popserver/config" [minlen=1]; -"internal/popserver" -> "internal/popserver/handler" [minlen=1]; -"internal/popserver" -> "internal/popserver/state" [minlen=1]; -"internal/popserver" -> "internal/popserver/utils" [minlen=1]; -"internal/popserver" -> "network/socket" [minlen=1]; -"internal/popserver/database" -> "internal/popserver/types" [minlen=1]; -"internal/popserver/handler" -> "internal/popserver/config" [minlen=1]; -"internal/popserver/handler" -> "internal/popserver/database" [minlen=1]; -"internal/popserver/handler" -> "internal/popserver/state" [minlen=1]; -"internal/popserver/handler" -> "internal/popserver/types" [minlen=1]; -"internal/popserver/handler" -> "internal/popserver/utils" [minlen=1]; -"internal/popserver/handler" -> "network/socket" [minlen=1]; -"internal/popserver/state" -> "internal/popserver/types" [minlen=1]; -"internal/popserver/state" -> "network/socket" [minlen=1]; -"internal/popserver/types" -> "network/socket" [minlen=1]; +"cli" -> "internal/crypto" [minlen=1]; +"cli" -> "internal/hub" [minlen=1]; +"cli" -> "internal/network" [minlen=1]; +"cli" -> "internal/network/socket" [minlen=1]; +"cli" -> "internal/singleton/config" [minlen=1]; +"cli" -> "internal/singleton/database" [minlen=1]; +"cli" -> "internal/singleton/state" [minlen=1]; +"cli" -> "internal/singleton/utils" [minlen=1]; +"cli" -> "internal/validation" [minlen=1]; +"internal/handler" -> "internal/handler/answer" [minlen=1]; +"internal/handler" -> "internal/handler/query" [minlen=1]; +"internal/handler" -> "internal/network/socket" [minlen=1]; +"internal/handler" -> "internal/singleton/utils" [minlen=1]; +"internal/handler" -> "internal/validation" [minlen=1]; +"internal/handler/answer" -> "internal/handler/channel" [minlen=1]; +"internal/handler/answer" -> "internal/handler/query" [minlen=1]; +"internal/handler/answer" -> "internal/singleton/state" [minlen=1]; +"internal/handler/channel" -> "internal/crypto" [minlen=1]; +"internal/handler/channel" -> "internal/network/socket" [minlen=1]; +"internal/handler/channel" -> "internal/singleton/config" [minlen=1]; +"internal/handler/channel" -> "internal/singleton/database" [minlen=1]; +"internal/handler/channel" -> "internal/singleton/state" [minlen=1]; +"internal/handler/channel" -> "internal/singleton/utils" [minlen=1]; +"internal/handler/channel" -> "internal/types" [minlen=1]; +"internal/handler/channel" -> "internal/validation" [minlen=1]; +"internal/handler/query" -> "internal/handler/channel" [minlen=1]; +"internal/handler/query" -> "internal/network/socket" [minlen=1]; +"internal/handler/query" -> "internal/singleton/config" [minlen=1]; +"internal/handler/query" -> "internal/singleton/database" [minlen=1]; +"internal/handler/query" -> "internal/singleton/state" [minlen=1]; +"internal/handler/query" -> "internal/singleton/utils" [minlen=1]; +"internal/hub" -> "internal/handler" [minlen=1]; +"internal/hub" -> "internal/handler/query" [minlen=1]; +"internal/hub" -> "internal/network/socket" [minlen=1]; +"internal/hub" -> "internal/singleton/config" [minlen=1]; +"internal/hub" -> "internal/singleton/database" [minlen=1]; +"internal/hub" -> "internal/singleton/state" [minlen=1]; +"internal/hub" -> "internal/singleton/utils" [minlen=1]; +"internal/network" -> "internal/network/socket" [minlen=1]; +"internal/network" -> "internal/popcha" [minlen=1]; +"internal/repository" -> "internal/types" [minlen=1]; +"internal/singleton/database" -> "internal/repository" [minlen=1]; +"internal/singleton/state" -> "internal/network/socket" [minlen=1]; +"internal/singleton/state" -> "internal/types" [minlen=1]; +"internal/singleton/utils" -> "internal/validation" [minlen=1]; +"internal/types" -> "internal/network/socket" [minlen=1]; } diff --git a/be1-go/docs/images/dependencies/dependencies.png b/be1-go/docs/images/dependencies/dependencies.png index d79cd342372f68dcb16bcd6bdb2ed59e64ac7ffa..5162e7209fb6338989c035c5d42aaa4591a3a1be 100644 GIT binary patch literal 343282 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 z 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 U&#o(@8FbIK&rreqR{ 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 Date: Sun, 2 Jun 2024 19:20:08 +0200 Subject: [PATCH 17/19] fix import cli --- be1-go/cli/cli.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/be1-go/cli/cli.go b/be1-go/cli/cli.go index 83f9b61542..111b441784 100644 --- a/be1-go/cli/cli.go +++ b/be1-go/cli/cli.go @@ -9,13 +9,13 @@ import ( "os" "popstellar/internal/crypto" hub2 "popstellar/internal/hub" - popstellar "popstellar/internal/logger" - network2 "popstellar/internal/network" + "popstellar/internal/logger" + "popstellar/internal/network" "popstellar/internal/network/socket" "popstellar/internal/old/hub" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" - state2 "popstellar/internal/singleton/state" + "popstellar/internal/singleton/state" "popstellar/internal/singleton/utils" "popstellar/internal/sqlite" "popstellar/internal/validation" @@ -107,7 +107,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { utils.InitUtils(l, schemaValidator) - state2.InitState(l) + state.InitState(l) config.InitConfig(point, serverPublicKey, serverSecretKey, s.ClientAddress, s.ServerAddress) @@ -117,7 +117,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { } for _, channel := range channels { - alreadyExist, errAnswer := state2.HasChannel(channel) + alreadyExist, errAnswer := state.HasChannel(channel) if errAnswer != nil { return nil, errAnswer } @@ -125,7 +125,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { continue } - errAnswer = state2.AddChannel(channel) + errAnswer = state.AddChannel(channel) if errAnswer != nil { return nil, errAnswer } @@ -137,7 +137,7 @@ func (s *ServerConfig) newHub(l *zerolog.Logger) (hub.Hub, error) { // Serve parses the CLI arguments and spawns a hub and a websocket server for // the server func Serve(cliCtx *cli.Context) error { - poplog := popstellar.Logger + poplog := logger.Logger configFilePath := cliCtx.String("config-file") var serverConfig ServerConfig @@ -169,12 +169,12 @@ func Serve(cliCtx *cli.Context) error { h.Start() // Start websocket server for clients - clientSrv := network2.NewServer(h, serverConfig.PrivateAddress, serverConfig.ClientPort, socket.ClientSocketType, + clientSrv := network.NewServer(h, serverConfig.PrivateAddress, serverConfig.ClientPort, socket.ClientSocketType, poplog.With().Str("role", "client websocket").Logger()) clientSrv.Start() // Start a websocket server for remote servers - serverSrv := network2.NewServer(h, serverConfig.PrivateAddress, serverConfig.ServerPort, socket.ServerSocketType, + serverSrv := network.NewServer(h, serverConfig.PrivateAddress, serverConfig.ServerPort, socket.ServerSocketType, poplog.With().Str("role", "server websocket").Logger()) serverSrv.Start() @@ -213,7 +213,7 @@ func Serve(cliCtx *cli.Context) error { go serverConnectionLoop(h, wg, done, serverConfig.OtherServers, updatedServersChan, &connectedServers) // Wait for a Ctrl-C - err = network2.WaitAndShutdownServers(cliCtx.Context, nil, clientSrv, serverSrv) + err = network.WaitAndShutdownServers(cliCtx.Context, nil, clientSrv, serverSrv) if err != nil { return err } @@ -303,7 +303,7 @@ func connectToServers(h hub.Hub, wg *sync.WaitGroup, done chan struct{}, servers func connectToSocket(address string, h hub.Hub, wg *sync.WaitGroup, done chan struct{}) error { - poplog := popstellar.Logger + poplog := logger.Logger urlString := fmt.Sprintf("ws://%s/server", address) u, err := url.Parse(urlString) From 32bd4bfe88928e4c27ba34a50211f81de7c715d2 Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 19:34:50 +0200 Subject: [PATCH 18/19] rename mocks to mock --- be1-go/internal/handler/answer/answer_test.go | 6 +++--- be1-go/internal/handler/channel/channel_test.go | 6 +++--- be1-go/internal/handler/channel/chirp_test.go | 4 ++-- be1-go/internal/handler/channel/coin_test.go | 10 +++++----- be1-go/internal/handler/channel/election_test.go | 4 ++-- be1-go/internal/handler/channel/federation_test.go | 4 ++-- be1-go/internal/handler/channel/lao_test.go | 4 ++-- be1-go/internal/handler/channel/reaction_test.go | 10 +++++----- be1-go/internal/handler/channel/root_test.go | 4 ++-- be1-go/internal/handler/incoming_message_test.go | 6 +++--- be1-go/internal/handler/query/catchup_test.go | 12 ++++++------ .../internal/handler/query/getmessagesbyid_test.go | 12 ++++++------ be1-go/internal/handler/query/greetserver_test.go | 12 ++++++------ be1-go/internal/handler/query/heartbeat_test.go | 14 +++++++------- be1-go/internal/handler/query/query_test.go | 6 +++--- be1-go/internal/handler/query/subscribe_test.go | 12 ++++++------ be1-go/internal/handler/query/unsubscribe_test.go | 14 +++++++------- be1-go/internal/{mocks => mock}/generator/chirp.go | 0 .../internal/{mocks => mock}/generator/election.go | 0 .../{mocks => mock}/generator/federation.go | 0 .../{mocks => mock}/generator/generatortest.go | 0 be1-go/internal/{mocks => mock}/generator/keys.go | 0 be1-go/internal/{mocks => mock}/generator/lao.go | 0 be1-go/internal/{mocks => mock}/generator/query.go | 0 .../internal/{mocks => mock}/generator/reaction.go | 0 be1-go/internal/{mocks => mock}/generator/root.go | 0 be1-go/internal/{mocks => mock}/repository.go | 2 +- be1-go/internal/{mocks => mock}/socket.go | 2 +- be1-go/internal/singleton/database/database.go | 4 ++-- be1-go/internal/sqlite/sqlite_test.go | 2 +- 30 files changed, 75 insertions(+), 75 deletions(-) rename be1-go/internal/{mocks => mock}/generator/chirp.go (100%) rename be1-go/internal/{mocks => mock}/generator/election.go (100%) rename be1-go/internal/{mocks => mock}/generator/federation.go (100%) rename be1-go/internal/{mocks => mock}/generator/generatortest.go (100%) rename be1-go/internal/{mocks => mock}/generator/keys.go (100%) rename be1-go/internal/{mocks => mock}/generator/lao.go (100%) rename be1-go/internal/{mocks => mock}/generator/query.go (100%) rename be1-go/internal/{mocks => mock}/generator/reaction.go (100%) rename be1-go/internal/{mocks => mock}/generator/root.go (100%) rename be1-go/internal/{mocks => mock}/repository.go (99%) rename be1-go/internal/{mocks => mock}/socket.go (98%) diff --git a/be1-go/internal/handler/answer/answer_test.go b/be1-go/internal/handler/answer/answer_test.go index ee2a781bc6..e31bfff2e5 100644 --- a/be1-go/internal/handler/answer/answer_test.go +++ b/be1-go/internal/handler/answer/answer_test.go @@ -12,8 +12,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/database" "popstellar/internal/singleton/utils" "popstellar/internal/validation" @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { } func Test_handleMessagesByChannel(t *testing.T) { - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) type input struct { diff --git a/be1-go/internal/handler/channel/channel_test.go b/be1-go/internal/handler/channel/channel_test.go index 47792751b3..399f33c046 100644 --- a/be1-go/internal/handler/channel/channel_test.go +++ b/be1-go/internal/handler/channel/channel_test.go @@ -9,8 +9,8 @@ import ( "io" "os" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/database" "popstellar/internal/singleton/utils" "popstellar/internal/validation" @@ -38,7 +38,7 @@ func TestMain(m *testing.M) { } func Test_handleChannel(t *testing.T) { - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) keypair := generator.GenerateKeyPair(t) diff --git a/be1-go/internal/handler/channel/chirp_test.go b/be1-go/internal/handler/channel/chirp_test.go index 9e9f8779eb..1dfef81915 100644 --- a/be1-go/internal/handler/channel/chirp_test.go +++ b/be1-go/internal/handler/channel/chirp_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" - mock2 "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + mock2 "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" diff --git a/be1-go/internal/handler/channel/coin_test.go b/be1-go/internal/handler/channel/coin_test.go index 4197eb36d8..0d6422faef 100644 --- a/be1-go/internal/handler/channel/coin_test.go +++ b/be1-go/internal/handler/channel/coin_test.go @@ -9,7 +9,7 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" + "popstellar/internal/mock" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" "popstellar/internal/types" @@ -23,7 +23,7 @@ type inputTestHandleChannelCoin struct { channelID string message message.Message hasError bool - sockets []*mocks.FakeSocket + sockets []*mock.FakeSocket } func Test_handleChannelCoin(t *testing.T) { @@ -34,7 +34,7 @@ func Test_handleChannelCoin(t *testing.T) { state2.SetState(subs, peers, queries, hubParams) - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) inputs := make([]inputTestHandleChannelCoin, 0) @@ -116,7 +116,7 @@ func Test_handleChannelCoin(t *testing.T) { } -func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository *mocks.Repository) inputTestHandleChannelCoin { +func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository *mock.Repository) inputTestHandleChannelCoin { laoID := messagedata.Hash(name) var sender = "M5ZychEi5rwm22FjwjNuljL1qMJWD2sE7oX9fcHNMDU=" var channelID = "/root/" + laoID + "/coin" @@ -137,7 +137,7 @@ func newSuccessTestHandleChannelCoin(t *testing.T, filename string, name string, mockRepository.On("StoreMessageAndData", channelID, m).Return(nil) - sockets := []*mocks.FakeSocket{ + sockets := []*mock.FakeSocket{ {Id: laoID + "0"}, {Id: laoID + "1"}, {Id: laoID + "2"}, diff --git a/be1-go/internal/handler/channel/election_test.go b/be1-go/internal/handler/channel/election_test.go index 7e0de413ff..1694bc512d 100644 --- a/be1-go/internal/handler/channel/election_test.go +++ b/be1-go/internal/handler/channel/election_test.go @@ -9,8 +9,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - mock2 "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + mock2 "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" diff --git a/be1-go/internal/handler/channel/federation_test.go b/be1-go/internal/handler/channel/federation_test.go index b8c7fc70b6..00c241ba7c 100644 --- a/be1-go/internal/handler/channel/federation_test.go +++ b/be1-go/internal/handler/channel/federation_test.go @@ -13,8 +13,8 @@ import ( "popstellar/internal/message/messagedata" "popstellar/internal/message/query" "popstellar/internal/message/query/method" - mock2 "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + mock2 "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" diff --git a/be1-go/internal/handler/channel/lao_test.go b/be1-go/internal/handler/channel/lao_test.go index b4d0939c3b..34d217eeb9 100644 --- a/be1-go/internal/handler/channel/lao_test.go +++ b/be1-go/internal/handler/channel/lao_test.go @@ -8,8 +8,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - mock2 "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + mock2 "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" diff --git a/be1-go/internal/handler/channel/reaction_test.go b/be1-go/internal/handler/channel/reaction_test.go index 11d83f84d7..227199a8d7 100644 --- a/be1-go/internal/handler/channel/reaction_test.go +++ b/be1-go/internal/handler/channel/reaction_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" state2 "popstellar/internal/singleton/state" @@ -36,7 +36,7 @@ func Test_handleChannelReaction(t *testing.T) { config.SetConfig(ownerPublicKey, serverPublicKey, serverSecretKey, "clientAddress", "serverAddress") - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) sender := "3yPmdBu8DM7jT30IKqkPjuFFIHnubO0z4E0dV7dR4sY=" @@ -222,7 +222,7 @@ func Test_handleChannelReaction(t *testing.T) { } func newReactionAddMsg(t *testing.T, channelID string, sender string, reactionCodePoint, chirpID string, timestamp int64, - mockRepository *mocks.Repository, hasInvalidField, isNotAttendee bool) message.Message { + mockRepository *mock.Repository, hasInvalidField, isNotAttendee bool) message.Message { msg := generator.NewReactionAddMsg(t, sender, nil, reactionCodePoint, chirpID, timestamp) @@ -244,7 +244,7 @@ func newReactionAddMsg(t *testing.T, channelID string, sender string, reactionCo } func newReactionDeleteMsg(t *testing.T, channelID string, sender string, reactionID string, timestamp int64, - mockRepository *mocks.Repository, hasInvalidField, hasNotReaction, isNotOwner, isNotAttendee bool) message.Message { + mockRepository *mock.Repository, hasInvalidField, hasNotReaction, isNotOwner, isNotAttendee bool) message.Message { msg := generator.NewReactionDeleteMsg(t, sender, nil, reactionID, timestamp) diff --git a/be1-go/internal/handler/channel/root_test.go b/be1-go/internal/handler/channel/root_test.go index 8a0c48d165..601abd2208 100644 --- a/be1-go/internal/handler/channel/root_test.go +++ b/be1-go/internal/handler/channel/root_test.go @@ -8,8 +8,8 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - mock2 "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + mock2 "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" diff --git a/be1-go/internal/handler/incoming_message_test.go b/be1-go/internal/handler/incoming_message_test.go index 99f4620011..097f2ea335 100644 --- a/be1-go/internal/handler/incoming_message_test.go +++ b/be1-go/internal/handler/incoming_message_test.go @@ -7,8 +7,8 @@ import ( "github.com/stretchr/testify/require" "io" "os" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/utils" "popstellar/internal/validation" "testing" @@ -62,7 +62,7 @@ func Test_handleIncomingMessage(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} err := HandleIncomingMessage(&fakeSocket, arg.message) require.Error(t, err) require.Contains(t, err.Error(), arg.contains) diff --git a/be1-go/internal/handler/query/catchup_test.go b/be1-go/internal/handler/query/catchup_test.go index bb748040f2..c3d78fa16b 100644 --- a/be1-go/internal/handler/query/catchup_test.go +++ b/be1-go/internal/handler/query/catchup_test.go @@ -4,8 +4,8 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/xerrors" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" "popstellar/internal/types" @@ -20,12 +20,12 @@ func Test_handleCatchUp(t *testing.T) { state.SetState(subs, peers, queries, hubParams) - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket ID int message []byte expected []message.Message @@ -37,7 +37,7 @@ func Test_handleCatchUp(t *testing.T) { // Test 1: successfully catchup 4 messages on a channel - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" messagesToCatchUp := []message.Message{ @@ -60,7 +60,7 @@ func Test_handleCatchUp(t *testing.T) { // Test 2: failed to catchup because DB is disconnected - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" diff --git a/be1-go/internal/handler/query/getmessagesbyid_test.go b/be1-go/internal/handler/query/getmessagesbyid_test.go index f8a9359892..185d2c08af 100644 --- a/be1-go/internal/handler/query/getmessagesbyid_test.go +++ b/be1-go/internal/handler/query/getmessagesbyid_test.go @@ -4,8 +4,8 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/xerrors" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" "popstellar/internal/types" @@ -20,12 +20,12 @@ func Test_handleGetMessagesByID(t *testing.T) { state.SetState(subs, peers, queries, hubParams) - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket ID int message []byte expected map[string][]message.Message @@ -37,7 +37,7 @@ func Test_handleGetMessagesByID(t *testing.T) { // Test 1: successfully handled getMessagesByID and sent the result - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} ID := 1 expected1 := make(map[string][]message.Message) @@ -73,7 +73,7 @@ func Test_handleGetMessagesByID(t *testing.T) { // Test 2: failed to handled getMessagesByID because DB is disconnected - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} ID = 2 paramsGetMessagesByID2 := make(map[string][]string) diff --git a/be1-go/internal/handler/query/greetserver_test.go b/be1-go/internal/handler/query/greetserver_test.go index 77657ea071..c133ddb549 100644 --- a/be1-go/internal/handler/query/greetserver_test.go +++ b/be1-go/internal/handler/query/greetserver_test.go @@ -4,8 +4,8 @@ import ( "github.com/stretchr/testify/require" "popstellar/internal/crypto" "popstellar/internal/message/query/method" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/config" "popstellar/internal/singleton/state" "popstellar/internal/types" @@ -27,7 +27,7 @@ func Test_handleGreetServer(t *testing.T) { type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket message []byte needGreet bool isError bool @@ -40,7 +40,7 @@ func Test_handleGreetServer(t *testing.T) { // Test 1: reply with greet server when receiving a greet server from a new server - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} args = append(args, input{ name: "Test 1", @@ -52,7 +52,7 @@ func Test_handleGreetServer(t *testing.T) { // Test 2: doesn't reply with greet server when already greeted the server - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} peers.AddPeerGreeted(fakeSocket.Id) @@ -66,7 +66,7 @@ func Test_handleGreetServer(t *testing.T) { // Test 3: return an error if the socket ID is already used by another server - fakeSocket = mocks.FakeSocket{Id: "3"} + fakeSocket = mock.FakeSocket{Id: "3"} err := peers.AddPeerInfo(fakeSocket.Id, method.GreetServerParams{}) require.NoError(t, err) diff --git a/be1-go/internal/handler/query/heartbeat_test.go b/be1-go/internal/handler/query/heartbeat_test.go index 50da019764..7780840c9e 100644 --- a/be1-go/internal/handler/query/heartbeat_test.go +++ b/be1-go/internal/handler/query/heartbeat_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/xerrors" "popstellar/internal/message/query/method" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/database" "popstellar/internal/singleton/state" "popstellar/internal/types" @@ -21,12 +21,12 @@ func Test_handleHeartbeat(t *testing.T) { state.SetState(subs, peers, queries, hubParams) - mockRepository := mocks.NewRepository(t) + mockRepository := mock.NewRepository(t) database.SetDatabase(mockRepository) type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket message []byte expected map[string][]string isError bool @@ -39,7 +39,7 @@ func Test_handleHeartbeat(t *testing.T) { // Test 1: successfully handled heartbeat with some messages to catching up - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} heartbeatMsgIDs1 := make(map[string][]string) heartbeatMsgIDs1["/root"] = []string{ @@ -77,7 +77,7 @@ func Test_handleHeartbeat(t *testing.T) { // Test 2: successfully handled heartbeat with nothing to catching up - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} heartbeatMsgIDs2 := make(map[string][]string) heartbeatMsgIDs2["/root"] = []string{ @@ -97,7 +97,7 @@ func Test_handleHeartbeat(t *testing.T) { // Test 3: failed to handled heartbeat because DB is disconnected - fakeSocket = mocks.FakeSocket{Id: "3"} + fakeSocket = mock.FakeSocket{Id: "3"} heartbeatMsgIDs3 := make(map[string][]string) heartbeatMsgIDs3["/root"] = []string{ diff --git a/be1-go/internal/handler/query/query_test.go b/be1-go/internal/handler/query/query_test.go index 58c9824421..bb5c2c4d7a 100644 --- a/be1-go/internal/handler/query/query_test.go +++ b/be1-go/internal/handler/query/query_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/require" "io" "os" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/utils" "popstellar/internal/validation" "testing" @@ -52,7 +52,7 @@ func Test_handleQuery(t *testing.T) { for _, arg := range args { t.Run(arg.name, func(t *testing.T) { - fakeSocket := mocks.FakeSocket{Id: "fakesocket"} + fakeSocket := mock.FakeSocket{Id: "fakesocket"} errAnswer := HandleQuery(&fakeSocket, arg.message) require.NotNil(t, errAnswer) require.Contains(t, errAnswer.Error(), arg.contains) diff --git a/be1-go/internal/handler/query/subscribe_test.go b/be1-go/internal/handler/query/subscribe_test.go index f01402d5ef..349f66ed62 100644 --- a/be1-go/internal/handler/query/subscribe_test.go +++ b/be1-go/internal/handler/query/subscribe_test.go @@ -2,8 +2,8 @@ package query import ( "github.com/stretchr/testify/require" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/state" "popstellar/internal/types" "testing" @@ -19,7 +19,7 @@ func Test_handleSubscribe(t *testing.T) { type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket ID int channel string message []byte @@ -31,7 +31,7 @@ func Test_handleSubscribe(t *testing.T) { // Test 1: successfully subscribe to a channel - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" @@ -49,7 +49,7 @@ func Test_handleSubscribe(t *testing.T) { // Test 2: failed to subscribe to an unknown channel - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" @@ -65,7 +65,7 @@ func Test_handleSubscribe(t *testing.T) { // cannot Subscribe to root - fakeSocket = mocks.FakeSocket{Id: "3"} + fakeSocket = mock.FakeSocket{Id: "3"} ID = 3 channel = "/root" diff --git a/be1-go/internal/handler/query/unsubscribe_test.go b/be1-go/internal/handler/query/unsubscribe_test.go index 8ceaa35800..de478f8993 100644 --- a/be1-go/internal/handler/query/unsubscribe_test.go +++ b/be1-go/internal/handler/query/unsubscribe_test.go @@ -2,8 +2,8 @@ package query import ( "github.com/stretchr/testify/require" - "popstellar/internal/mocks" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock" + "popstellar/internal/mock/generator" "popstellar/internal/singleton/state" "popstellar/internal/types" "testing" @@ -19,7 +19,7 @@ func Test_handleUnsubscribe(t *testing.T) { type input struct { name string - socket mocks.FakeSocket + socket mock.FakeSocket ID int channel string message []byte @@ -31,7 +31,7 @@ func Test_handleUnsubscribe(t *testing.T) { // Test 1: successfully unsubscribe from a subscribed channel - fakeSocket := mocks.FakeSocket{Id: "1"} + fakeSocket := mock.FakeSocket{Id: "1"} ID := 1 channel := "/root/lao1" @@ -52,7 +52,7 @@ func Test_handleUnsubscribe(t *testing.T) { // Test 2: failed to unsubscribe because not subscribed to channel - fakeSocket = mocks.FakeSocket{Id: "2"} + fakeSocket = mock.FakeSocket{Id: "2"} ID = 2 channel = "/root/lao2" @@ -71,7 +71,7 @@ func Test_handleUnsubscribe(t *testing.T) { // Test 3: failed to unsubscribe because unknown channel - fakeSocket = mocks.FakeSocket{Id: "3"} + fakeSocket = mock.FakeSocket{Id: "3"} ID = 3 channel = "/root/lao3" @@ -87,7 +87,7 @@ func Test_handleUnsubscribe(t *testing.T) { // Test 3: failed to unsubscribe because cannot unsubscribe from root channel - fakeSocket = mocks.FakeSocket{Id: "4"} + fakeSocket = mock.FakeSocket{Id: "4"} ID = 4 channel = "/root" diff --git a/be1-go/internal/mocks/generator/chirp.go b/be1-go/internal/mock/generator/chirp.go similarity index 100% rename from be1-go/internal/mocks/generator/chirp.go rename to be1-go/internal/mock/generator/chirp.go diff --git a/be1-go/internal/mocks/generator/election.go b/be1-go/internal/mock/generator/election.go similarity index 100% rename from be1-go/internal/mocks/generator/election.go rename to be1-go/internal/mock/generator/election.go diff --git a/be1-go/internal/mocks/generator/federation.go b/be1-go/internal/mock/generator/federation.go similarity index 100% rename from be1-go/internal/mocks/generator/federation.go rename to be1-go/internal/mock/generator/federation.go diff --git a/be1-go/internal/mocks/generator/generatortest.go b/be1-go/internal/mock/generator/generatortest.go similarity index 100% rename from be1-go/internal/mocks/generator/generatortest.go rename to be1-go/internal/mock/generator/generatortest.go diff --git a/be1-go/internal/mocks/generator/keys.go b/be1-go/internal/mock/generator/keys.go similarity index 100% rename from be1-go/internal/mocks/generator/keys.go rename to be1-go/internal/mock/generator/keys.go diff --git a/be1-go/internal/mocks/generator/lao.go b/be1-go/internal/mock/generator/lao.go similarity index 100% rename from be1-go/internal/mocks/generator/lao.go rename to be1-go/internal/mock/generator/lao.go diff --git a/be1-go/internal/mocks/generator/query.go b/be1-go/internal/mock/generator/query.go similarity index 100% rename from be1-go/internal/mocks/generator/query.go rename to be1-go/internal/mock/generator/query.go diff --git a/be1-go/internal/mocks/generator/reaction.go b/be1-go/internal/mock/generator/reaction.go similarity index 100% rename from be1-go/internal/mocks/generator/reaction.go rename to be1-go/internal/mock/generator/reaction.go diff --git a/be1-go/internal/mocks/generator/root.go b/be1-go/internal/mock/generator/root.go similarity index 100% rename from be1-go/internal/mocks/generator/root.go rename to be1-go/internal/mock/generator/root.go diff --git a/be1-go/internal/mocks/repository.go b/be1-go/internal/mock/repository.go similarity index 99% rename from be1-go/internal/mocks/repository.go rename to be1-go/internal/mock/repository.go index e4fceb7456..caab6721a7 100644 --- a/be1-go/internal/mocks/repository.go +++ b/be1-go/internal/mock/repository.go @@ -1,6 +1,6 @@ // Code generated by mockery v2.42.1. DO NOT EDIT. -package mocks +package mock import ( messagedata "popstellar/internal/message/messagedata" diff --git a/be1-go/internal/mocks/socket.go b/be1-go/internal/mock/socket.go similarity index 98% rename from be1-go/internal/mocks/socket.go rename to be1-go/internal/mock/socket.go index c2bd0f2c51..9796eadcb5 100644 --- a/be1-go/internal/mocks/socket.go +++ b/be1-go/internal/mock/socket.go @@ -1,4 +1,4 @@ -package mocks +package mock import ( "popstellar/internal/message/query/method/message" diff --git a/be1-go/internal/singleton/database/database.go b/be1-go/internal/singleton/database/database.go index 3a9f1d845e..a05872d2e9 100644 --- a/be1-go/internal/singleton/database/database.go +++ b/be1-go/internal/singleton/database/database.go @@ -2,7 +2,7 @@ package database import ( "popstellar/internal/message/answer" - "popstellar/internal/mocks" + "popstellar/internal/mock" repository2 "popstellar/internal/repository" "sync" ) @@ -18,7 +18,7 @@ func InitDatabase(db repository2.Repository) { // ONLY FOR TEST PURPOSE // SetDatabase is only here to be used to reset the database before each test -func SetDatabase(mockRepo *mocks.Repository) { +func SetDatabase(mockRepo *mock.Repository) { instance = mockRepo } diff --git a/be1-go/internal/sqlite/sqlite_test.go b/be1-go/internal/sqlite/sqlite_test.go index 50cc7eae0a..98b0a9ba90 100644 --- a/be1-go/internal/sqlite/sqlite_test.go +++ b/be1-go/internal/sqlite/sqlite_test.go @@ -11,7 +11,7 @@ import ( "popstellar/internal/crypto" "popstellar/internal/message/messagedata" "popstellar/internal/message/query/method/message" - "popstellar/internal/mocks/generator" + "popstellar/internal/mock/generator" "popstellar/internal/types" "sort" "testing" From 33b623048bf7408d5ae01de05e7205a5ce41444f Mon Sep 17 00:00:00 2001 From: stuart Date: Sun, 2 Jun 2024 19:37:50 +0200 Subject: [PATCH 19/19] update sonar conf --- be1-go/sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/be1-go/sonar-project.properties b/be1-go/sonar-project.properties index a824653c1c..9f337fd702 100644 --- a/be1-go/sonar-project.properties +++ b/be1-go/sonar-project.properties @@ -7,7 +7,7 @@ sonar.go.coverage.reportPaths=./coverage.out # Path patterns of the source files sonar.sources=. -sonar.exclusions=**/*_test.go,**/test/**, **/mocks/** +sonar.exclusions=**/*_test.go,**/test/**, **/mock/** # Path patterns of the test files sonar.tests=.