From 96dd8173fa61ff8e8f508171ff57913c0d2c347e Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:44:03 -0700 Subject: [PATCH 1/2] fix(v24): accept day-name strings in SystemDayOfWeek unmarshal Keyfactor Command serializes WeeklyModel.Days as day-name strings (e.g. "Monday") in some API responses, but SystemDayOfWeek.UnmarshalJSON only accepted JSON integers, causing Weekly-scheduled resources to fail to deserialize. Try the integer form first, preserving existing enum validation, and fall back to the existing Parse() day-name mapping when the payload is a JSON string. Malformed strings and out-of-range ints still error clearly. Applies to both v1 and v2 API packages in this module. --- .../keyfactor/v1/model_system_day_of_week.go | 31 +++-- .../v1/model_system_day_of_week_test.go | 117 ++++++++++++++++++ .../keyfactor/v2/model_system_day_of_week.go | 31 +++-- .../v2/model_system_day_of_week_test.go | 117 ++++++++++++++++++ 4 files changed, 276 insertions(+), 20 deletions(-) create mode 100644 v24/api/keyfactor/v1/model_system_day_of_week_test.go create mode 100644 v24/api/keyfactor/v2/model_system_day_of_week_test.go diff --git a/v24/api/keyfactor/v1/model_system_day_of_week.go b/v24/api/keyfactor/v1/model_system_day_of_week.go index c137e17..be750a0 100644 --- a/v24/api/keyfactor/v1/model_system_day_of_week.go +++ b/v24/api/keyfactor/v1/model_system_day_of_week.go @@ -79,20 +79,31 @@ var AllowedSystemDayOfWeekEnumValues = []SystemDayOfWeek{ } func (v *SystemDayOfWeek) UnmarshalJSON(src []byte) error { + // Keyfactor Command has, across API versions, serialized this enum both + // as a JSON integer (e.g. 1) and as a day-name string (e.g. "Monday"). + // Try the integer form first to preserve the original generated + // validation against AllowedSystemDayOfWeekEnumValues. var value int32 - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SystemDayOfWeek(value) - for _, existing := range AllowedSystemDayOfWeekEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil + if err := json.Unmarshal(src, &value); err == nil { + enumTypeValue := SystemDayOfWeek(value) + for _, existing := range AllowedSystemDayOfWeekEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } } + + return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + } + + // Fall back to the string form (e.g. "Monday") using the existing Parse + // helper, which maps day names to their enum values. + var strValue string + if err := json.Unmarshal(src, &strValue); err != nil { + return fmt.Errorf("SystemDayOfWeek must be a JSON integer or day-name string, got %s", string(src)) } - return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + return v.Parse(strValue) } // NewSystemDayOfWeekFromValue returns a pointer to a valid SystemDayOfWeek diff --git a/v24/api/keyfactor/v1/model_system_day_of_week_test.go b/v24/api/keyfactor/v1/model_system_day_of_week_test.go new file mode 100644 index 0000000..2201cd8 --- /dev/null +++ b/v24/api/keyfactor/v1/model_system_day_of_week_test.go @@ -0,0 +1,117 @@ +/* +Copyright 2025 Keyfactor +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain a +copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. See the License for +the specific language governing permissions and limitations under the +License. +*/ + +package v1 + +import ( + "encoding/json" + "testing" + "time" +) + +// TestSystemDayOfWeek_UnmarshalJSON_IntForm verifies that the original +// generated wire form (a JSON integer) still deserializes correctly. +func TestSystemDayOfWeek_UnmarshalJSON_IntForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`1`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling int form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_StringForm covers the regression from +// GitHub issue #185: Keyfactor Command v25.5 serializes WeeklyModel.Days as +// day-name strings (e.g. "Monday") rather than integers. +func TestSystemDayOfWeek_UnmarshalJSON_StringForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`"Monday"`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling string form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_InvalidString verifies a malformed day +// name still produces a clear error rather than silently defaulting. +func TestSystemDayOfWeek_UnmarshalJSON_InvalidString(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`"Funday"`), &got) + if err == nil { + t.Fatalf("expected error for invalid day-name string, got nil (value=%v)", got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt verifies an out-of-range +// integer still produces a clear error rather than silently accepting it. +func TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`42`), &got) + if err == nil { + t.Fatalf("expected error for out-of-range int, got nil (value=%v)", got) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayNameStrings is the full round-trip +// regression test for issue #185: a Weekly-shaped schedule payload as +// returned by GET /CertificateAuthority on a v25.5 Command instance must +// deserialize into KeyfactorCommonSchedulingModelsWeeklyModel without error. +func TestWeeklyModel_UnmarshalJSON_DayNameStrings(t *testing.T) { + payload := `{"Days":["Monday","Friday"],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with day-name strings: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } + + wantTime, err := time.Parse(time.RFC3339, "2000-01-01T07:00:00Z") + if err != nil { + t.Fatalf("failed to parse expected time: %v", err) + } + if model.Time == nil || !model.Time.Equal(wantTime) { + t.Errorf("Time: expected %v, got %v", wantTime, model.Time) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayIndexInts verifies the pre-v25.5 integer +// wire form of WeeklyModel.Days still round-trips correctly, guarding +// against a regression in the other direction. +func TestWeeklyModel_UnmarshalJSON_DayIndexInts(t *testing.T) { + payload := `{"Days":[1,5],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with int days: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } +} diff --git a/v24/api/keyfactor/v2/model_system_day_of_week.go b/v24/api/keyfactor/v2/model_system_day_of_week.go index bf9ae58..d2a4988 100644 --- a/v24/api/keyfactor/v2/model_system_day_of_week.go +++ b/v24/api/keyfactor/v2/model_system_day_of_week.go @@ -79,20 +79,31 @@ var AllowedSystemDayOfWeekEnumValues = []SystemDayOfWeek{ } func (v *SystemDayOfWeek) UnmarshalJSON(src []byte) error { + // Keyfactor Command has, across API versions, serialized this enum both + // as a JSON integer (e.g. 1) and as a day-name string (e.g. "Monday"). + // Try the integer form first to preserve the original generated + // validation against AllowedSystemDayOfWeekEnumValues. var value int32 - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SystemDayOfWeek(value) - for _, existing := range AllowedSystemDayOfWeekEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil + if err := json.Unmarshal(src, &value); err == nil { + enumTypeValue := SystemDayOfWeek(value) + for _, existing := range AllowedSystemDayOfWeekEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } } + + return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + } + + // Fall back to the string form (e.g. "Monday") using the existing Parse + // helper, which maps day names to their enum values. + var strValue string + if err := json.Unmarshal(src, &strValue); err != nil { + return fmt.Errorf("SystemDayOfWeek must be a JSON integer or day-name string, got %s", string(src)) } - return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + return v.Parse(strValue) } // NewSystemDayOfWeekFromValue returns a pointer to a valid SystemDayOfWeek diff --git a/v24/api/keyfactor/v2/model_system_day_of_week_test.go b/v24/api/keyfactor/v2/model_system_day_of_week_test.go new file mode 100644 index 0000000..eb2a288 --- /dev/null +++ b/v24/api/keyfactor/v2/model_system_day_of_week_test.go @@ -0,0 +1,117 @@ +/* +Copyright 2025 Keyfactor +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain a +copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. See the License for +the specific language governing permissions and limitations under the +License. +*/ + +package v2 + +import ( + "encoding/json" + "testing" + "time" +) + +// TestSystemDayOfWeek_UnmarshalJSON_IntForm verifies that the original +// generated wire form (a JSON integer) still deserializes correctly. +func TestSystemDayOfWeek_UnmarshalJSON_IntForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`1`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling int form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_StringForm covers the regression from +// GitHub issue #185: Keyfactor Command v25.5 serializes WeeklyModel.Days as +// day-name strings (e.g. "Monday") rather than integers. +func TestSystemDayOfWeek_UnmarshalJSON_StringForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`"Monday"`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling string form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_InvalidString verifies a malformed day +// name still produces a clear error rather than silently defaulting. +func TestSystemDayOfWeek_UnmarshalJSON_InvalidString(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`"Funday"`), &got) + if err == nil { + t.Fatalf("expected error for invalid day-name string, got nil (value=%v)", got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt verifies an out-of-range +// integer still produces a clear error rather than silently accepting it. +func TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`42`), &got) + if err == nil { + t.Fatalf("expected error for out-of-range int, got nil (value=%v)", got) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayNameStrings is the full round-trip +// regression test for issue #185: a Weekly-shaped schedule payload as +// returned by GET /CertificateAuthority on a v25.5 Command instance must +// deserialize into KeyfactorCommonSchedulingModelsWeeklyModel without error. +func TestWeeklyModel_UnmarshalJSON_DayNameStrings(t *testing.T) { + payload := `{"Days":["Monday","Friday"],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with day-name strings: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } + + wantTime, err := time.Parse(time.RFC3339, "2000-01-01T07:00:00Z") + if err != nil { + t.Fatalf("failed to parse expected time: %v", err) + } + if model.Time == nil || !model.Time.Equal(wantTime) { + t.Errorf("Time: expected %v, got %v", wantTime, model.Time) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayIndexInts verifies the pre-v25.5 integer +// wire form of WeeklyModel.Days still round-trips correctly, guarding +// against a regression in the other direction. +func TestWeeklyModel_UnmarshalJSON_DayIndexInts(t *testing.T) { + payload := `{"Days":[1,5],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with int days: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } +} From e2633f6f62564aea1d0f79df29bd380b4105b9fb Mon Sep 17 00:00:00 2001 From: spbsoluble <1661003+spbsoluble@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:44:16 -0700 Subject: [PATCH 2/2] fix(v25): accept day-name strings in SystemDayOfWeek unmarshal Fixes keyfactor-pub/terraform-provider-keyfactor#185: Keyfactor Command v25.5 serializes WeeklyModel.Days as day-name strings (e.g. "Monday") in GET /CertificateAuthority responses, but SystemDayOfWeek.UnmarshalJSON only accepted JSON integers, causing any Weekly-scheduled CA to fail to deserialize. Try the integer form first, preserving existing enum validation, and fall back to the existing Parse() day-name mapping when the payload is a JSON string. Malformed strings and out-of-range ints still error clearly. Applies to both v1 and v2 API packages in this module. --- .../keyfactor/v1/model_system_day_of_week.go | 31 +++-- .../v1/model_system_day_of_week_test.go | 117 ++++++++++++++++++ .../keyfactor/v2/model_system_day_of_week.go | 31 +++-- .../v2/model_system_day_of_week_test.go | 117 ++++++++++++++++++ 4 files changed, 276 insertions(+), 20 deletions(-) create mode 100644 v25/api/keyfactor/v1/model_system_day_of_week_test.go create mode 100644 v25/api/keyfactor/v2/model_system_day_of_week_test.go diff --git a/v25/api/keyfactor/v1/model_system_day_of_week.go b/v25/api/keyfactor/v1/model_system_day_of_week.go index d8b8dc7..f29e86c 100644 --- a/v25/api/keyfactor/v1/model_system_day_of_week.go +++ b/v25/api/keyfactor/v1/model_system_day_of_week.go @@ -79,20 +79,31 @@ var AllowedSystemDayOfWeekEnumValues = []SystemDayOfWeek{ } func (v *SystemDayOfWeek) UnmarshalJSON(src []byte) error { + // Keyfactor Command has, across API versions, serialized this enum both + // as a JSON integer (e.g. 1) and as a day-name string (e.g. "Monday"). + // Try the integer form first to preserve the original generated + // validation against AllowedSystemDayOfWeekEnumValues. var value int32 - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SystemDayOfWeek(value) - for _, existing := range AllowedSystemDayOfWeekEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil + if err := json.Unmarshal(src, &value); err == nil { + enumTypeValue := SystemDayOfWeek(value) + for _, existing := range AllowedSystemDayOfWeekEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } } + + return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + } + + // Fall back to the string form (e.g. "Monday") using the existing Parse + // helper, which maps day names to their enum values. + var strValue string + if err := json.Unmarshal(src, &strValue); err != nil { + return fmt.Errorf("SystemDayOfWeek must be a JSON integer or day-name string, got %s", string(src)) } - return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + return v.Parse(strValue) } // NewSystemDayOfWeekFromValue returns a pointer to a valid SystemDayOfWeek diff --git a/v25/api/keyfactor/v1/model_system_day_of_week_test.go b/v25/api/keyfactor/v1/model_system_day_of_week_test.go new file mode 100644 index 0000000..2201cd8 --- /dev/null +++ b/v25/api/keyfactor/v1/model_system_day_of_week_test.go @@ -0,0 +1,117 @@ +/* +Copyright 2025 Keyfactor +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain a +copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. See the License for +the specific language governing permissions and limitations under the +License. +*/ + +package v1 + +import ( + "encoding/json" + "testing" + "time" +) + +// TestSystemDayOfWeek_UnmarshalJSON_IntForm verifies that the original +// generated wire form (a JSON integer) still deserializes correctly. +func TestSystemDayOfWeek_UnmarshalJSON_IntForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`1`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling int form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_StringForm covers the regression from +// GitHub issue #185: Keyfactor Command v25.5 serializes WeeklyModel.Days as +// day-name strings (e.g. "Monday") rather than integers. +func TestSystemDayOfWeek_UnmarshalJSON_StringForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`"Monday"`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling string form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_InvalidString verifies a malformed day +// name still produces a clear error rather than silently defaulting. +func TestSystemDayOfWeek_UnmarshalJSON_InvalidString(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`"Funday"`), &got) + if err == nil { + t.Fatalf("expected error for invalid day-name string, got nil (value=%v)", got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt verifies an out-of-range +// integer still produces a clear error rather than silently accepting it. +func TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`42`), &got) + if err == nil { + t.Fatalf("expected error for out-of-range int, got nil (value=%v)", got) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayNameStrings is the full round-trip +// regression test for issue #185: a Weekly-shaped schedule payload as +// returned by GET /CertificateAuthority on a v25.5 Command instance must +// deserialize into KeyfactorCommonSchedulingModelsWeeklyModel without error. +func TestWeeklyModel_UnmarshalJSON_DayNameStrings(t *testing.T) { + payload := `{"Days":["Monday","Friday"],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with day-name strings: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } + + wantTime, err := time.Parse(time.RFC3339, "2000-01-01T07:00:00Z") + if err != nil { + t.Fatalf("failed to parse expected time: %v", err) + } + if model.Time == nil || !model.Time.Equal(wantTime) { + t.Errorf("Time: expected %v, got %v", wantTime, model.Time) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayIndexInts verifies the pre-v25.5 integer +// wire form of WeeklyModel.Days still round-trips correctly, guarding +// against a regression in the other direction. +func TestWeeklyModel_UnmarshalJSON_DayIndexInts(t *testing.T) { + payload := `{"Days":[1,5],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with int days: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } +} diff --git a/v25/api/keyfactor/v2/model_system_day_of_week.go b/v25/api/keyfactor/v2/model_system_day_of_week.go index 65de2b2..5b07ab4 100644 --- a/v25/api/keyfactor/v2/model_system_day_of_week.go +++ b/v25/api/keyfactor/v2/model_system_day_of_week.go @@ -79,20 +79,31 @@ var AllowedSystemDayOfWeekEnumValues = []SystemDayOfWeek{ } func (v *SystemDayOfWeek) UnmarshalJSON(src []byte) error { + // Keyfactor Command has, across API versions, serialized this enum both + // as a JSON integer (e.g. 1) and as a day-name string (e.g. "Monday"). + // Try the integer form first to preserve the original generated + // validation against AllowedSystemDayOfWeekEnumValues. var value int32 - err := json.Unmarshal(src, &value) - if err != nil { - return err - } - enumTypeValue := SystemDayOfWeek(value) - for _, existing := range AllowedSystemDayOfWeekEnumValues { - if existing == enumTypeValue { - *v = enumTypeValue - return nil + if err := json.Unmarshal(src, &value); err == nil { + enumTypeValue := SystemDayOfWeek(value) + for _, existing := range AllowedSystemDayOfWeekEnumValues { + if existing == enumTypeValue { + *v = enumTypeValue + return nil + } } + + return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + } + + // Fall back to the string form (e.g. "Monday") using the existing Parse + // helper, which maps day names to their enum values. + var strValue string + if err := json.Unmarshal(src, &strValue); err != nil { + return fmt.Errorf("SystemDayOfWeek must be a JSON integer or day-name string, got %s", string(src)) } - return fmt.Errorf("%+v is not a valid SystemDayOfWeek", value) + return v.Parse(strValue) } // NewSystemDayOfWeekFromValue returns a pointer to a valid SystemDayOfWeek diff --git a/v25/api/keyfactor/v2/model_system_day_of_week_test.go b/v25/api/keyfactor/v2/model_system_day_of_week_test.go new file mode 100644 index 0000000..eb2a288 --- /dev/null +++ b/v25/api/keyfactor/v2/model_system_day_of_week_test.go @@ -0,0 +1,117 @@ +/* +Copyright 2025 Keyfactor +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain a +copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +OR CONDITIONS OF ANY KIND, either express or implied. See the License for +the specific language governing permissions and limitations under the +License. +*/ + +package v2 + +import ( + "encoding/json" + "testing" + "time" +) + +// TestSystemDayOfWeek_UnmarshalJSON_IntForm verifies that the original +// generated wire form (a JSON integer) still deserializes correctly. +func TestSystemDayOfWeek_UnmarshalJSON_IntForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`1`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling int form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_StringForm covers the regression from +// GitHub issue #185: Keyfactor Command v25.5 serializes WeeklyModel.Days as +// day-name strings (e.g. "Monday") rather than integers. +func TestSystemDayOfWeek_UnmarshalJSON_StringForm(t *testing.T) { + var got SystemDayOfWeek + if err := json.Unmarshal([]byte(`"Monday"`), &got); err != nil { + t.Fatalf("unexpected error unmarshaling string form: %v", err) + } + if got != SYSTEMDAYOFWEEK_Monday { + t.Errorf("expected %v, got %v", SYSTEMDAYOFWEEK_Monday, got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_InvalidString verifies a malformed day +// name still produces a clear error rather than silently defaulting. +func TestSystemDayOfWeek_UnmarshalJSON_InvalidString(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`"Funday"`), &got) + if err == nil { + t.Fatalf("expected error for invalid day-name string, got nil (value=%v)", got) + } +} + +// TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt verifies an out-of-range +// integer still produces a clear error rather than silently accepting it. +func TestSystemDayOfWeek_UnmarshalJSON_OutOfRangeInt(t *testing.T) { + var got SystemDayOfWeek + err := json.Unmarshal([]byte(`42`), &got) + if err == nil { + t.Fatalf("expected error for out-of-range int, got nil (value=%v)", got) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayNameStrings is the full round-trip +// regression test for issue #185: a Weekly-shaped schedule payload as +// returned by GET /CertificateAuthority on a v25.5 Command instance must +// deserialize into KeyfactorCommonSchedulingModelsWeeklyModel without error. +func TestWeeklyModel_UnmarshalJSON_DayNameStrings(t *testing.T) { + payload := `{"Days":["Monday","Friday"],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with day-name strings: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } + + wantTime, err := time.Parse(time.RFC3339, "2000-01-01T07:00:00Z") + if err != nil { + t.Fatalf("failed to parse expected time: %v", err) + } + if model.Time == nil || !model.Time.Equal(wantTime) { + t.Errorf("Time: expected %v, got %v", wantTime, model.Time) + } +} + +// TestWeeklyModel_UnmarshalJSON_DayIndexInts verifies the pre-v25.5 integer +// wire form of WeeklyModel.Days still round-trips correctly, guarding +// against a regression in the other direction. +func TestWeeklyModel_UnmarshalJSON_DayIndexInts(t *testing.T) { + payload := `{"Days":[1,5],"Time":"2000-01-01T07:00:00Z"}` + + var model KeyfactorCommonSchedulingModelsWeeklyModel + if err := json.Unmarshal([]byte(payload), &model); err != nil { + t.Fatalf("unexpected error unmarshaling WeeklyModel with int days: %v", err) + } + + wantDays := []SystemDayOfWeek{SYSTEMDAYOFWEEK_Monday, SYSTEMDAYOFWEEK_Friday} + if len(model.Days) != len(wantDays) { + t.Fatalf("expected %d days, got %d (%v)", len(wantDays), len(model.Days), model.Days) + } + for i, want := range wantDays { + if model.Days[i] != want { + t.Errorf("Days[%d]: expected %v, got %v", i, want, model.Days[i]) + } + } +}