]> git.giacomolli.uk - onechat/blobdiff - whatsapp_import_test.go
Use both logs for WhatsApp import cutoffs
[onechat] / whatsapp_import_test.go
index 5f7d21c656a4aa4d65771bae93217e811e4c47a2..1e24039da497f31381327604efcc6eedbe1ebada 100644 (file)
@@ -56,7 +56,7 @@ func TestWhatsAppImportSplitsDaysAndMapsOnlyOwner(t *testing.T) {
                },
        }
 
                },
        }
 
-       plan, err := whatsappImportPlan(t.Context(), []string{path}, nil, names, "Sam Owner", time.UTC)
+       plan, err := whatsappImportPlan(t.Context(), []string{path}, nil, nil, names, "Sam Owner", time.UTC)
        require.NoError(t, err)
        require.Len(t, plan.added, 5)
        require.Equal(t, "2025-05-20T13:06:44Z", plan.added[0].Date)
        require.NoError(t, err)
        require.Len(t, plan.added, 5)
        require.Equal(t, "2025-05-20T13:06:44Z", plan.added[0].Date)
@@ -78,12 +78,12 @@ func TestWhatsAppImportSkipsHeldDaysAndMessagesAfterLiveCutoff(t *testing.T) {
        old := []DatedMessage{
                {
                        Kind: "work",
        old := []DatedMessage{
                {
                        Kind: "work",
-                       Text: "[WhatsApp] Live, private chat other@lid, Sunday 2025-06-08\n10:00 Ada: Later",
+                       Text: "[WhatsApp] Book Club, private chat other@lid, Sunday 2025-06-08\n10:00 Ada: Later",
                        Date: "2025-06-08T10:01:00Z",
                },
                {
                        Kind: "work",
                        Date: "2025-06-08T10:01:00Z",
                },
                {
                        Kind: "work",
-                       Text: "[WhatsApp] Live, private chat other@lid, Tuesday 2025-06-03\n18:41 Ada: First\n18:42 Ada: Last",
+                       Text: "[WhatsApp] Book Club, private chat other@lid, Tuesday 2025-06-03\n18:41 Ada: First\n18:42 Ada: Last",
                        Date: "2025-06-03T18:43:00Z",
                },
                {
                        Date: "2025-06-03T18:43:00Z",
                },
                {
@@ -93,7 +93,7 @@ func TestWhatsAppImportSkipsHeldDaysAndMessagesAfterLiveCutoff(t *testing.T) {
                },
        }
 
                },
        }
 
-       plan, err := whatsappImportPlan(t.Context(), []string{path}, old, map[string]WhatsAppChat{}, "Sam Owner", time.UTC)
+       plan, err := whatsappImportPlan(t.Context(), []string{path}, old, nil, map[string]WhatsAppChat{}, "Sam Owner", time.UTC)
        require.NoError(t, err)
        require.Equal(t, "2025-06-03T18:41:00Z", plan.cutoff.Format(time.RFC3339))
        require.Equal(t, 1, plan.skipped)
        require.NoError(t, err)
        require.Equal(t, "2025-06-03T18:41:00Z", plan.cutoff.Format(time.RFC3339))
        require.Equal(t, 1, plan.skipped)
@@ -108,11 +108,11 @@ func TestWhatsAppImportCutoffUsesLocalTimeAndExcludesBoundary(t *testing.T) {
        path := whatsappImportZip(t, "Local", "[03/06/2025, 18:40:59] Ada: Before\n[03/06/2025, 18:41:00] Ada: Boundary\n[03/06/2025, 18:41:01] Ada: After\n")
        old := []DatedMessage{{
                Kind: "work",
        path := whatsappImportZip(t, "Local", "[03/06/2025, 18:40:59] Ada: Before\n[03/06/2025, 18:41:00] Ada: Boundary\n[03/06/2025, 18:41:01] Ada: After\n")
        old := []DatedMessage{{
                Kind: "work",
-               Text: "[WhatsApp] Live, group live@g.us, Tuesday 2025-06-03\n18:41 Ada: First",
+               Text: "[WhatsApp] Local, group live@g.us, Tuesday 2025-06-03\n18:41 Ada: First",
                Date: "2025-06-04T01:00:00Z",
        }}
 
                Date: "2025-06-04T01:00:00Z",
        }}
 
-       plan, err := whatsappImportPlan(t.Context(), []string{path}, old, map[string]WhatsAppChat{}, "", time.FixedZone("TEST", -3*60*60))
+       plan, err := whatsappImportPlan(t.Context(), []string{path}, old, nil, map[string]WhatsAppChat{}, "", time.FixedZone("TEST", -3*60*60))
        require.NoError(t, err)
        require.Equal(t, "2025-06-03T18:41:00-03:00", plan.cutoff.Format(time.RFC3339))
        require.Len(t, plan.added, 1)
        require.NoError(t, err)
        require.Equal(t, "2025-06-03T18:41:00-03:00", plan.cutoff.Format(time.RFC3339))
        require.Len(t, plan.added, 1)
@@ -130,16 +130,16 @@ func TestWhatsAppImportKeepsSystemSenderEvenWithOwnerName(t *testing.T) {
 
 func TestWhatsAppImportRefusesOverlappingInputs(t *testing.T) {
        path := whatsappImportSample(t)
 
 func TestWhatsAppImportRefusesOverlappingInputs(t *testing.T) {
        path := whatsappImportSample(t)
-       _, err := whatsappImportPlan(t.Context(), []string{path, path}, nil, map[string]WhatsAppChat{}, "", time.UTC)
+       _, err := whatsappImportPlan(t.Context(), []string{path, path}, nil, nil, map[string]WhatsAppChat{}, "", time.UTC)
        require.ErrorContains(t, err, "inputs overlap")
 }
 
 func TestWhatsAppImportSkipsAllDaysOnALaterStep(t *testing.T) {
        path := whatsappImportSample(t)
        require.ErrorContains(t, err, "inputs overlap")
 }
 
 func TestWhatsAppImportSkipsAllDaysOnALaterStep(t *testing.T) {
        path := whatsappImportSample(t)
-       first, err := whatsappImportPlan(t.Context(), []string{path}, nil, nil, "Sam Owner", time.UTC)
+       first, err := whatsappImportPlan(t.Context(), []string{path}, nil, nil, nil, "Sam Owner", time.UTC)
        require.NoError(t, err)
 
        require.NoError(t, err)
 
-       second, err := whatsappImportPlan(t.Context(), []string{path}, first.added, nil, "Sam Owner", time.UTC)
+       second, err := whatsappImportPlan(t.Context(), []string{path}, first.added, nil, nil, "Sam Owner", time.UTC)
        require.NoError(t, err)
        require.Empty(t, second.added)
        require.Equal(t, 5, second.skipped)
        require.NoError(t, err)
        require.Empty(t, second.added)
        require.Equal(t, 5, second.skipped)
@@ -149,7 +149,7 @@ func TestWhatsAppImportSkipsAllDaysOnALaterStep(t *testing.T) {
 func TestWhatsAppImportMergesChatsByDate(t *testing.T) {
        later := whatsappImportZip(t, "Later", "[02/01/2025, 08:00:00] Ada: Later\n")
        earlier := whatsappImportZip(t, "Earlier", "[01/01/2025, 08:00:00] Bea: Earlier\n")
 func TestWhatsAppImportMergesChatsByDate(t *testing.T) {
        later := whatsappImportZip(t, "Later", "[02/01/2025, 08:00:00] Ada: Later\n")
        earlier := whatsappImportZip(t, "Earlier", "[01/01/2025, 08:00:00] Bea: Earlier\n")
-       plan, err := whatsappImportPlan(t.Context(), []string{later, earlier}, nil, nil, "", time.UTC)
+       plan, err := whatsappImportPlan(t.Context(), []string{later, earlier}, nil, nil, nil, "", time.UTC)
        require.NoError(t, err)
        require.Len(t, plan.added, 2)
        require.Contains(t, plan.added[0].Text, "[WhatsApp] Earlier,")
        require.NoError(t, err)
        require.Len(t, plan.added, 2)
        require.Contains(t, plan.added[0].Text, "[WhatsApp] Earlier,")
@@ -242,11 +242,13 @@ func TestWhatsAppImportPlanCommandDoesNotChangeAgentOrCallModel(t *testing.T) {
        }})
 
        before := rebuildTestSnapshot(t, agent.dir)
        }})
 
        before := rebuildTestSnapshot(t, agent.dir)
+
        var report strings.Builder
        var report strings.Builder
+
        require.NoError(t, whatsappImport(t.Context(), []string{"-n", whatsappImportSample(t)}, &report))
        require.Equal(t, before, rebuildTestSnapshot(t, agent.dir))
 
        require.NoError(t, whatsappImport(t.Context(), []string{"-n", whatsappImportSample(t)}, &report))
        require.Equal(t, before, rebuildTestSnapshot(t, agent.dir))
 
-       for _, want := range []string{"chats: 1", "Book Club", "batches: 5", "dates: ", "cutoff: none", "bytes: ", "messages: 6", "estimated calls: 8", "owner: unknown"} {
+       for _, want := range []string{"chats: 1", "Book Club", "batches: 5", "dates: ", "cutoff: none", "bytes: ", "messages: 6", "estimated calls: 8 (about 1.3 per message, limit 1500)", "owner: unknown"} {
                require.Contains(t, report.String(), want)
        }
 
                require.Contains(t, report.String(), want)
        }
 
@@ -266,15 +268,18 @@ func TestWhatsAppImportDoesNotRebuildWhenAllDaysAreHeld(t *testing.T) {
        agent := newRebuildTestAgent(t)
        dir := filepath.Dir(agent.dir)
        t.Setenv("ONECHAT_DIR", dir)
        agent := newRebuildTestAgent(t)
        dir := filepath.Dir(agent.dir)
        t.Setenv("ONECHAT_DIR", dir)
+
        path := whatsappImportSample(t)
        path := whatsappImportSample(t)
-       plan, err := whatsappImportPlan(t.Context(), []string{path}, nil, nil, "", time.UTC)
+       plan, err := whatsappImportPlan(t.Context(), []string{path}, nil, nil, nil, "", time.UTC)
        require.NoError(t, err)
 
        rebuildTestLog(t, agent.dir, plan.added)
        require.NoError(t, os.WriteFile(filepath.Join(dir, "config.json"), []byte("not model settings"), 0o600))
 
        before := rebuildTestSnapshot(t, agent.dir)
        require.NoError(t, err)
 
        rebuildTestLog(t, agent.dir, plan.added)
        require.NoError(t, os.WriteFile(filepath.Join(dir, "config.json"), []byte("not model settings"), 0o600))
 
        before := rebuildTestSnapshot(t, agent.dir)
+
        var report strings.Builder
        var report strings.Builder
+
        require.NoError(t, whatsappImport(t.Context(), []string{path}, &report))
        require.Contains(t, report.String(), "batches: 0")
        require.Contains(t, report.String(), "estimated calls: 0")
        require.NoError(t, whatsappImport(t.Context(), []string{path}, &report))
        require.Contains(t, report.String(), "batches: 0")
        require.Contains(t, report.String(), "estimated calls: 0")
@@ -284,6 +289,7 @@ func TestWhatsAppImportDoesNotRebuildWhenAllDaysAreHeld(t *testing.T) {
 func TestWhatsAppImportReadsOnlyLocalSessionNames(t *testing.T) {
        dir := t.TempDir()
        whatsappTestSession(t, dir, true)
 func TestWhatsAppImportReadsOnlyLocalSessionNames(t *testing.T) {
        dir := t.TempDir()
        whatsappTestSession(t, dir, true)
+
        session := &WhatsApp{
                dir: filepath.Join(dir, whatsappDirName),
        }
        session := &WhatsApp{
                dir: filepath.Join(dir, whatsappDirName),
        }
@@ -311,6 +317,57 @@ func TestWhatsAppImportReadsOnlyLocalSessionNames(t *testing.T) {
        require.NotContains(t, names, "Owner LID")
 }
 
        require.NotContains(t, names, "Owner LID")
 }
 
+func TestWhatsAppImportCutoffUsesEachChatAndBothLogs(t *testing.T) {
+       path := whatsappImportZip(t, "Plans", "[03/01/2025, 09:59:59] Ada: Before\n[03/01/2025, 10:00:00] Ada: Boundary\n[03/01/2025, 10:01:00] Ada: After\n")
+       target := []DatedMessage{{
+               Kind: "work",
+               Text: "[WhatsApp] Plans, group example@g.us, Friday 2025-01-03\n10:00 Ada: Target first\n10:30 Ada: Target last",
+               Date: "2025-01-03T10:30:00Z",
+       }}
+
+       root := []DatedMessage{
+               {
+                       Kind: "work",
+                       Text: "[WhatsApp] Other, group other@g.us, Wednesday 2025-01-01\n08:00 Bea: Other chat",
+                       Date: "2025-01-01T08:00:00Z",
+               },
+               {
+                       Kind: "work",
+                       Text: "[WhatsApp] Plans, group example@g.us, Saturday 2025-01-04\n10:00 Ada: Later batch",
+                       Date: "2025-01-04T10:00:00Z",
+               },
+       }
+
+       testCases := []struct {
+               name   string
+               target []DatedMessage
+               root   []DatedMessage
+       }{
+               {
+                       name:   "target holds the first live batch",
+                       target: target,
+                       root:   root,
+               },
+               {
+                       name:   "root holds the first live batch",
+                       target: root,
+                       root:   target,
+               },
+       }
+
+       for _, tc := range testCases {
+               t.Run(tc.name, func(t *testing.T) {
+                       plan, err := whatsappImportPlan(t.Context(), []string{path}, tc.target, tc.root, nil, "", time.UTC)
+                       require.NoError(t, err)
+                       require.Equal(t, "2025-01-03T10:00:00Z", plan.cutoff.Format(time.RFC3339))
+                       require.Len(t, plan.added, 1)
+                       require.Contains(t, plan.added[0].Text, "Before")
+                       require.NotContains(t, plan.added[0].Text, "Boundary")
+                       require.NotContains(t, plan.added[0].Text, "After")
+               })
+       }
+}
+
 func whatsappImportSample(t *testing.T) string {
        t.Helper()
 
 func whatsappImportSample(t *testing.T) string {
        t.Helper()