diff --git a/sa/model.go b/sa/model.go index 974fd6360dd..f327eece611 100644 --- a/sa/model.go +++ b/sa/model.go @@ -400,7 +400,7 @@ type orderModelv2 struct { Error []byte CertificateSerial string BeganProcessing bool - CertificateProfileName string + CertificateProfileName *string } type orderToAuthzModel struct { @@ -464,7 +464,7 @@ func orderToModelv2(order *corepb.Order) (*orderModelv2, error) { Created: order.Created.AsTime(), BeganProcessing: order.BeganProcessing, CertificateSerial: order.CertificateSerial, - CertificateProfileName: order.CertificateProfileName, + CertificateProfileName: &order.CertificateProfileName, } if order.Error != nil { @@ -481,6 +481,10 @@ func orderToModelv2(order *corepb.Order) (*orderModelv2, error) { } func modelToOrderv2(om *orderModelv2) (*corepb.Order, error) { + profile := "" + if om.CertificateProfileName != nil { + profile = *om.CertificateProfileName + } order := &corepb.Order{ Id: om.ID, RegistrationID: om.RegistrationID, @@ -488,7 +492,7 @@ func modelToOrderv2(om *orderModelv2) (*corepb.Order, error) { Created: timestamppb.New(om.Created), CertificateSerial: om.CertificateSerial, BeganProcessing: om.BeganProcessing, - CertificateProfileName: om.CertificateProfileName, + CertificateProfileName: profile, } if len(om.Error) > 0 { var problem corepb.ProblemDetails diff --git a/sa/sa.go b/sa/sa.go index c7be24ae5ef..e3c7137d46c 100644 --- a/sa/sa.go +++ b/sa/sa.go @@ -654,7 +654,7 @@ func (ssa *SQLStorageAuthority) NewOrderAndAuthzs(ctx context.Context, req *sapb RegistrationID: req.NewOrder.RegistrationID, Expires: req.NewOrder.Expires.AsTime(), Created: created, - CertificateProfileName: req.NewOrder.CertificateProfileName, + CertificateProfileName: &req.NewOrder.CertificateProfileName, } err = tx.Insert(ctx, &omv2) orderID = omv2.ID diff --git a/sa/sa_test.go b/sa/sa_test.go index e358082ac68..de4aabd58ab 100644 --- a/sa/sa_test.go +++ b/sa/sa_test.go @@ -1354,29 +1354,17 @@ func TestOrderWithOrderModelv1(t *testing.T) { } func TestOrderWithOrderModelv2(t *testing.T) { + // This test requires the config-next db schema to run. if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { t.Skip() } - // The feature must be set before the SA is constructed because of a - // conditional on this feature in //sa/database.go. + sa, fc, cleanup := initSA(t) + defer cleanup() + features.Set(features.Config{MultipleCertificateProfiles: true}) defer features.Reset() - fc := clock.NewFake() - fc.Set(time.Date(2015, 3, 4, 5, 0, 0, 0, time.UTC)) - - dbMap, err := DBMapForTest(vars.DBConnSA) - test.AssertNotError(t, err, "Couldn't create dbMap") - - saro, err := NewSQLStorageAuthorityRO(dbMap, nil, metrics.NoopRegisterer, 1, 0, fc, log) - test.AssertNotError(t, err, "Couldn't create SARO") - - sa, err := NewSQLStorageAuthorityWrapping(saro, dbMap, metrics.NoopRegisterer) - test.AssertNotError(t, err, "Couldn't create SA") - defer test.ResetBoulderTestDatabase(t) - - // Create a test registration to reference reg := createWorkingRegistration(t, sa) authzExpires := fc.Now().Add(time.Hour) authzID := createPendingAuthorization(t, sa, "example.com", authzExpires) @@ -1482,6 +1470,82 @@ func TestOrderWithOrderModelv2(t *testing.T) { test.AssertDeepEquals(t, storedOrderNoName, expectedOrderNoName) } +func TestOrderModelMigration(t *testing.T) { + // This test requires the config-next db schema to run. + if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { + t.Skip() + } + + sa, fc, cleanup := initSA(t) + defer cleanup() + + reg := createWorkingRegistration(t, sa) + + // Create an order using the v1 model + authzID := createPendingAuthorization(t, sa, "example.com", fc.Now().Add(time.Hour)) + order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ + NewOrder: &sapb.NewOrderRequest{ + RegistrationID: reg.Id, + Expires: timestamppb.New(fc.Now().Add(2 * time.Hour)), + DnsNames: []string{"example.com"}, + V2Authorizations: []int64{authzID}, + }, + }) + if err != nil { + t.Fatalf("failed to insert order using orderModelv1: %s", err) + } + + // Retrieve that order using the v2 model + features.Set(features.Config{MultipleCertificateProfiles: true}) + defer features.Reset() + storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id}) + if err != nil { + t.Fatalf("failed to retrieve order using orderModelv2: %s", err) + } + if storedOrder.CertificateProfileName != "" { + t.Errorf("order inserted with v1 schema should have empty profilename, instead got %q", storedOrder.CertificateProfileName) + } +} + +func TestOrderModelMigrationRollback(t *testing.T) { + // This test requires the config-next db schema to run. + if !strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") { + t.Skip() + } + + sa, fc, cleanup := initSA(t) + defer cleanup() + + reg := createWorkingRegistration(t, sa) + + // Create an order using the v2 model + features.Set(features.Config{MultipleCertificateProfiles: true}) + defer features.Reset() + authzID := createPendingAuthorization(t, sa, "example.com", fc.Now().Add(time.Hour)) + order, err := sa.NewOrderAndAuthzs(context.Background(), &sapb.NewOrderAndAuthzsRequest{ + NewOrder: &sapb.NewOrderRequest{ + RegistrationID: reg.Id, + Expires: timestamppb.New(fc.Now().Add(2 * time.Hour)), + DnsNames: []string{"example.com"}, + V2Authorizations: []int64{authzID}, + CertificateProfileName: "asdf", + }, + }) + if err != nil { + t.Fatalf("failed to insert order using orderModelv2: %s", err) + } + + // Retrieve that order using the v1 model + features.Reset() + storedOrder, err := sa.GetOrder(context.Background(), &sapb.OrderRequest{Id: order.Id}) + if err != nil { + t.Fatalf("failed to retrieve order using orderModelv1: %s", err) + } + if storedOrder.CertificateProfileName != "" { + t.Errorf("order retrieved with v1 schema should have empty profilename, instead got %q", storedOrder.CertificateProfileName) + } +} + // TestGetAuthorization2NoRows ensures that the GetAuthorization2 function returns // the correct error when there are no results for the provided ID. func TestGetAuthorization2NoRows(t *testing.T) {